aboutsummaryrefslogtreecommitdiff
path: root/SOURCES
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2022-09-11 23:18:31 +0200
committerJan200101 <sentrycraft123@gmail.com>2022-09-11 23:18:31 +0200
commitedbfb7abc2ff480fb7218e6a792602ac15f16e65 (patch)
tree81651715d126e5266fdb80031b5ef934cb875bad /SOURCES
parentf8f69532dab32443fc37f1c3ccd5ca0933c903e8 (diff)
downloadkernel-fsync-edbfb7abc2ff480fb7218e6a792602ac15f16e65.tar.gz
kernel-fsync-edbfb7abc2ff480fb7218e6a792602ac15f16e65.zip
kernel 5.19.7
Diffstat (limited to 'SOURCES')
-rw-r--r--SOURCES/0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch34
-rw-r--r--SOURCES/amdgpu-regression.patch1178
-rw-r--r--SOURCES/asus-linux.patch2509
-rw-r--r--SOURCES/kernel-aarch64-debug-fedora.config1
-rw-r--r--SOURCES/kernel-aarch64-debug-rhel.config1
-rw-r--r--SOURCES/kernel-aarch64-fedora.config1
-rw-r--r--SOURCES/kernel-aarch64-rhel.config1
-rw-r--r--SOURCES/patch-5.19-redhat.patch8
8 files changed, 3729 insertions, 4 deletions
diff --git a/SOURCES/0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch b/SOURCES/0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch
new file mode 100644
index 0000000..e68df11
--- /dev/null
+++ b/SOURCES/0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch
@@ -0,0 +1,34 @@
+From 4b4ce124699c160925e5fdeb147a78f79d38351f Mon Sep 17 00:00:00 2001
+From: Simon May <simon.may@protonmail.ch>
+Date: Sun, 19 Sep 2021 23:45:59 +0200
+Subject: [PATCH] Revert "PCI: Add a REBAR size quirk for Sapphire RX 5600 XT
+ Pulse"
+
+This reverts commit 907830b0fc9e374d00f3c83de5e426157b482c01.
+---
+ drivers/pci/pci.c | 9 +--------
+ 1 file changed, 1 insertion(+), 8 deletions(-)
+
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index 3f353572588d..1c8cc4b98f95 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -3637,14 +3637,7 @@ u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar)
+ return 0;
+
+ pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap);
+- cap &= PCI_REBAR_CAP_SIZES;
+-
+- /* Sapphire RX 5600 XT Pulse has an invalid cap dword for BAR 0 */
+- if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x731f &&
+- bar == 0 && cap == 0x7000)
+- cap = 0x3f000;
+-
+- return cap >> 4;
++ return (cap & PCI_REBAR_CAP_SIZES) >> 4;
+ }
+ EXPORT_SYMBOL(pci_rebar_get_possible_sizes);
+
+--
+2.30.2
+
diff --git a/SOURCES/amdgpu-regression.patch b/SOURCES/amdgpu-regression.patch
new file mode 100644
index 0000000..8503700
--- /dev/null
+++ b/SOURCES/amdgpu-regression.patch
@@ -0,0 +1,1178 @@
+From c9cad937c0c58618fe5b0310fd539a854dc1ae95 Mon Sep 17 00:00:00 2001
+From: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
+Date: Fri, 8 Apr 2022 04:18:43 +0530
+Subject: drm/amdgpu: add drm buddy support to amdgpu
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+- Switch to drm buddy allocator
+- Add resource cursor support for drm buddy
+
+v2(Matthew Auld):
+ - replace spinlock with mutex as we call kmem_cache_zalloc
+ (..., GFP_KERNEL) in drm_buddy_alloc() function
+
+ - lock drm_buddy_block_trim() function as it calls
+ mark_free/mark_split are all globally visible
+
+v3(Matthew Auld):
+ - remove trim method error handling as we address the failure case
+ at drm_buddy_block_trim() function
+
+v4:
+ - fix warnings reported by kernel test robot <lkp@intel.com>
+
+v5:
+ - fix merge conflict issue
+
+v6:
+ - fix warnings reported by kernel test robot <lkp@intel.com>
+
+v7:
+ - remove DRM_BUDDY_RANGE_ALLOCATION flag usage
+
+v8:
+ - keep DRM_BUDDY_RANGE_ALLOCATION flag usage
+ - resolve conflicts created by drm/amdgpu: remove VRAM accounting v2
+
+v9(Christian):
+ - merged the below patch
+ - drm/amdgpu: move vram inline functions into a header
+ - rename label name as fallback
+ - move struct amdgpu_vram_mgr to amdgpu_vram_mgr.h
+ - remove unnecessary flags from struct amdgpu_vram_reservation
+ - rewrite block NULL check condition
+ - change else style as per coding standard
+ - rewrite the node max size
+ - add a helper function to fetch the first entry from the list
+
+v10(Christian):
+ - rename amdgpu_get_node() function name as amdgpu_vram_mgr_first_block
+
+v11:
+ - if size is not aligned with min_page_size, enable is_contiguous flag,
+ therefore, the size round up to the power of two and trimmed to the
+ original size.
+v12:
+ - rename the function names having prefix as amdgpu_vram_mgr_*()
+ - modify the round_up() logic conforming to contiguous flag enablement
+ or if size is not aligned to min_block_size
+ - modify the trim logic
+ - rename node as block wherever applicable
+
+Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
+Acked-by: Christian König <christian.koenig@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220407224843.2416-1-Arunpravin.PaneerSelvam@amd.com
+Signed-off-by: Christian König <christian.koenig@amd.com>
+---
+ drivers/gpu/drm/Kconfig | 1 +
+ drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h | 97 +++++--
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 10 +-
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 359 +++++++++++++++----------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 89 ++++++
+ 5 files changed, 380 insertions(+), 176 deletions(-)
+ create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+
+diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
+index f1422bee3dcc..5133c3f028ab 100644
+--- a/drivers/gpu/drm/Kconfig
++++ b/drivers/gpu/drm/Kconfig
+@@ -280,6 +280,7 @@ config DRM_AMDGPU
+ select HWMON
+ select BACKLIGHT_CLASS_DEVICE
+ select INTERVAL_TREE
++ select DRM_BUDDY
+ help
+ Choose this option if you have a recent AMD Radeon graphics card.
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
+index acfa207cf970..6546552e596c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
+@@ -30,12 +30,15 @@
+ #include <drm/ttm/ttm_resource.h>
+ #include <drm/ttm/ttm_range_manager.h>
+
++#include "amdgpu_vram_mgr.h"
++
+ /* state back for walking over vram_mgr and gtt_mgr allocations */
+ struct amdgpu_res_cursor {
+ uint64_t start;
+ uint64_t size;
+ uint64_t remaining;
+- struct drm_mm_node *node;
++ void *node;
++ uint32_t mem_type;
+ };
+
+ /**
+@@ -52,27 +55,63 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
+ uint64_t start, uint64_t size,
+ struct amdgpu_res_cursor *cur)
+ {
++ struct drm_buddy_block *block;
++ struct list_head *head, *next;
+ struct drm_mm_node *node;
+
+- if (!res || res->mem_type == TTM_PL_SYSTEM) {
+- cur->start = start;
+- cur->size = size;
+- cur->remaining = size;
+- cur->node = NULL;
+- WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
+- return;
+- }
++ if (!res)
++ goto fallback;
+
+ BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
+
+- node = to_ttm_range_mgr_node(res)->mm_nodes;
+- while (start >= node->size << PAGE_SHIFT)
+- start -= node++->size << PAGE_SHIFT;
++ cur->mem_type = res->mem_type;
++
++ switch (cur->mem_type) {
++ case TTM_PL_VRAM:
++ head = &to_amdgpu_vram_mgr_resource(res)->blocks;
++
++ block = list_first_entry_or_null(head,
++ struct drm_buddy_block,
++ link);
++ if (!block)
++ goto fallback;
++
++ while (start >= amdgpu_vram_mgr_block_size(block)) {
++ start -= amdgpu_vram_mgr_block_size(block);
++
++ next = block->link.next;
++ if (next != head)
++ block = list_entry(next, struct drm_buddy_block, link);
++ }
++
++ cur->start = amdgpu_vram_mgr_block_start(block) + start;
++ cur->size = min(amdgpu_vram_mgr_block_size(block) - start, size);
++ cur->remaining = size;
++ cur->node = block;
++ break;
++ case TTM_PL_TT:
++ node = to_ttm_range_mgr_node(res)->mm_nodes;
++ while (start >= node->size << PAGE_SHIFT)
++ start -= node++->size << PAGE_SHIFT;
++
++ cur->start = (node->start << PAGE_SHIFT) + start;
++ cur->size = min((node->size << PAGE_SHIFT) - start, size);
++ cur->remaining = size;
++ cur->node = node;
++ break;
++ default:
++ goto fallback;
++ }
+
+- cur->start = (node->start << PAGE_SHIFT) + start;
+- cur->size = min((node->size << PAGE_SHIFT) - start, size);
++ return;
++
++fallback:
++ cur->start = start;
++ cur->size = size;
+ cur->remaining = size;
+- cur->node = node;
++ cur->node = NULL;
++ WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
++ return;
+ }
+
+ /**
+@@ -85,7 +124,9 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
+ */
+ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
+ {
+- struct drm_mm_node *node = cur->node;
++ struct drm_buddy_block *block;
++ struct drm_mm_node *node;
++ struct list_head *next;
+
+ BUG_ON(size > cur->remaining);
+
+@@ -99,9 +140,27 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
+ return;
+ }
+
+- cur->node = ++node;
+- cur->start = node->start << PAGE_SHIFT;
+- cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
++ switch (cur->mem_type) {
++ case TTM_PL_VRAM:
++ block = cur->node;
++
++ next = block->link.next;
++ block = list_entry(next, struct drm_buddy_block, link);
++
++ cur->node = block;
++ cur->start = amdgpu_vram_mgr_block_start(block);
++ cur->size = min(amdgpu_vram_mgr_block_size(block), cur->remaining);
++ break;
++ case TTM_PL_TT:
++ node = cur->node;
++
++ cur->node = ++node;
++ cur->start = node->start << PAGE_SHIFT;
++ cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
++ break;
++ default:
++ return;
++ }
+ }
+
+ #endif
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+index 9120ae80ef52..6a70818039dd 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+@@ -26,6 +26,7 @@
+
+ #include <linux/dma-direction.h>
+ #include <drm/gpu_scheduler.h>
++#include "amdgpu_vram_mgr.h"
+ #include "amdgpu.h"
+
+ #define AMDGPU_PL_GDS (TTM_PL_PRIV + 0)
+@@ -38,15 +39,6 @@
+
+ #define AMDGPU_POISON 0xd0bed0be
+
+-struct amdgpu_vram_mgr {
+- struct ttm_resource_manager manager;
+- struct drm_mm mm;
+- spinlock_t lock;
+- struct list_head reservations_pending;
+- struct list_head reserved_pages;
+- atomic64_t vis_usage;
+-};
+-
+ struct amdgpu_gtt_mgr {
+ struct ttm_resource_manager manager;
+ struct drm_mm mm;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+index 0a7611648573..49e4092f447f 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+@@ -32,8 +32,10 @@
+ #include "atom.h"
+
+ struct amdgpu_vram_reservation {
+- struct list_head node;
+- struct drm_mm_node mm_node;
++ u64 start;
++ u64 size;
++ struct list_head allocated;
++ struct list_head blocks;
+ };
+
+ static inline struct amdgpu_vram_mgr *
+@@ -186,18 +188,18 @@ const struct attribute_group amdgpu_vram_mgr_attr_group = {
+ };
+
+ /**
+- * amdgpu_vram_mgr_vis_size - Calculate visible node size
++ * amdgpu_vram_mgr_vis_size - Calculate visible block size
+ *
+ * @adev: amdgpu_device pointer
+- * @node: MM node structure
++ * @block: DRM BUDDY block structure
+ *
+- * Calculate how many bytes of the MM node are inside visible VRAM
++ * Calculate how many bytes of the DRM BUDDY block are inside visible VRAM
+ */
+ static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
+- struct drm_mm_node *node)
++ struct drm_buddy_block *block)
+ {
+- uint64_t start = node->start << PAGE_SHIFT;
+- uint64_t end = (node->size + node->start) << PAGE_SHIFT;
++ u64 start = amdgpu_vram_mgr_block_start(block);
++ u64 end = start + amdgpu_vram_mgr_block_size(block);
+
+ if (start >= adev->gmc.visible_vram_size)
+ return 0;
+@@ -218,9 +220,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
+ {
+ struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
+ struct ttm_resource *res = bo->tbo.resource;
+- unsigned pages = res->num_pages;
+- struct drm_mm_node *mm;
+- u64 usage;
++ struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
++ struct drm_buddy_block *block;
++ u64 usage = 0;
+
+ if (amdgpu_gmc_vram_full_visible(&adev->gmc))
+ return amdgpu_bo_size(bo);
+@@ -228,9 +230,8 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
+ if (res->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
+ return 0;
+
+- mm = &container_of(res, struct ttm_range_mgr_node, base)->mm_nodes[0];
+- for (usage = 0; pages; pages -= mm->size, mm++)
+- usage += amdgpu_vram_mgr_vis_size(adev, mm);
++ list_for_each_entry(block, &vres->blocks, link)
++ usage += amdgpu_vram_mgr_vis_size(adev, block);
+
+ return usage;
+ }
+@@ -240,23 +241,30 @@ static void amdgpu_vram_mgr_do_reserve(struct ttm_resource_manager *man)
+ {
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+ struct amdgpu_device *adev = to_amdgpu_device(mgr);
+- struct drm_mm *mm = &mgr->mm;
++ struct drm_buddy *mm = &mgr->mm;
+ struct amdgpu_vram_reservation *rsv, *temp;
++ struct drm_buddy_block *block;
+ uint64_t vis_usage;
+
+- list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node) {
+- if (drm_mm_reserve_node(mm, &rsv->mm_node))
++ list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks) {
++ if (drm_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size,
++ rsv->size, mm->chunk_size, &rsv->allocated,
++ DRM_BUDDY_RANGE_ALLOCATION))
++ continue;
++
++ block = amdgpu_vram_mgr_first_block(&rsv->allocated);
++ if (!block)
+ continue;
+
+ dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Succeeded\n",
+- rsv->mm_node.start, rsv->mm_node.size);
++ rsv->start, rsv->size);
+
+- vis_usage = amdgpu_vram_mgr_vis_size(adev, &rsv->mm_node);
++ vis_usage = amdgpu_vram_mgr_vis_size(adev, block);
+ atomic64_add(vis_usage, &mgr->vis_usage);
+ spin_lock(&man->bdev->lru_lock);
+- man->usage += rsv->mm_node.size << PAGE_SHIFT;
++ man->usage += rsv->size;
+ spin_unlock(&man->bdev->lru_lock);
+- list_move(&rsv->node, &mgr->reserved_pages);
++ list_move(&rsv->blocks, &mgr->reserved_pages);
+ }
+ }
+
+@@ -278,14 +286,16 @@ int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr,
+ if (!rsv)
+ return -ENOMEM;
+
+- INIT_LIST_HEAD(&rsv->node);
+- rsv->mm_node.start = start >> PAGE_SHIFT;
+- rsv->mm_node.size = size >> PAGE_SHIFT;
++ INIT_LIST_HEAD(&rsv->allocated);
++ INIT_LIST_HEAD(&rsv->blocks);
+
+- spin_lock(&mgr->lock);
+- list_add_tail(&rsv->node, &mgr->reservations_pending);
++ rsv->start = start;
++ rsv->size = size;
++
++ mutex_lock(&mgr->lock);
++ list_add_tail(&rsv->blocks, &mgr->reservations_pending);
+ amdgpu_vram_mgr_do_reserve(&mgr->manager);
+- spin_unlock(&mgr->lock);
++ mutex_unlock(&mgr->lock);
+
+ return 0;
+ }
+@@ -307,19 +317,19 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
+ struct amdgpu_vram_reservation *rsv;
+ int ret;
+
+- spin_lock(&mgr->lock);
++ mutex_lock(&mgr->lock);
+
+- list_for_each_entry(rsv, &mgr->reservations_pending, node) {
+- if ((rsv->mm_node.start <= start) &&
+- (start < (rsv->mm_node.start + rsv->mm_node.size))) {
++ list_for_each_entry(rsv, &mgr->reservations_pending, blocks) {
++ if (rsv->start <= start &&
++ (start < (rsv->start + rsv->size))) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+- list_for_each_entry(rsv, &mgr->reserved_pages, node) {
+- if ((rsv->mm_node.start <= start) &&
+- (start < (rsv->mm_node.start + rsv->mm_node.size))) {
++ list_for_each_entry(rsv, &mgr->reserved_pages, blocks) {
++ if (rsv->start <= start &&
++ (start < (rsv->start + rsv->size))) {
+ ret = 0;
+ goto out;
+ }
+@@ -327,32 +337,10 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
+
+ ret = -ENOENT;
+ out:
+- spin_unlock(&mgr->lock);
++ mutex_unlock(&mgr->lock);
+ return ret;
+ }
+
+-/**
+- * amdgpu_vram_mgr_virt_start - update virtual start address
+- *
+- * @mem: ttm_resource to update
+- * @node: just allocated node
+- *
+- * Calculate a virtual BO start address to easily check if everything is CPU
+- * accessible.
+- */
+-static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
+- struct drm_mm_node *node)
+-{
+- unsigned long start;
+-
+- start = node->start + node->size;
+- if (start > mem->num_pages)
+- start -= mem->num_pages;
+- else
+- start = 0;
+- mem->start = max(mem->start, start);
+-}
+-
+ /**
+ * amdgpu_vram_mgr_new - allocate new ranges
+ *
+@@ -368,46 +356,44 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
+ const struct ttm_place *place,
+ struct ttm_resource **res)
+ {
+- unsigned long lpfn, num_nodes, pages_per_node, pages_left, pages;
++ u64 vis_usage = 0, max_bytes, cur_size, min_block_size;
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+ struct amdgpu_device *adev = to_amdgpu_device(mgr);
+- uint64_t vis_usage = 0, mem_bytes, max_bytes;
+- struct ttm_range_mgr_node *node;
+- struct drm_mm *mm = &mgr->mm;
+- enum drm_mm_insert_mode mode;
+- unsigned i;
++ struct amdgpu_vram_mgr_resource *vres;
++ u64 size, remaining_size, lpfn, fpfn;
++ struct drm_buddy *mm = &mgr->mm;
++ struct drm_buddy_block *block;
++ unsigned long pages_per_block;
+ int r;
+
+- lpfn = place->lpfn;
++ lpfn = place->lpfn << PAGE_SHIFT;
+ if (!lpfn)
+- lpfn = man->size >> PAGE_SHIFT;
++ lpfn = man->size;
++
++ fpfn = place->fpfn << PAGE_SHIFT;
+
+ max_bytes = adev->gmc.mc_vram_size;
+ if (tbo->type != ttm_bo_type_kernel)
+ max_bytes -= AMDGPU_VM_RESERVED_VRAM;
+
+- mem_bytes = tbo->base.size;
+ if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
+- pages_per_node = ~0ul;
+- num_nodes = 1;
++ pages_per_block = ~0ul;
+ } else {
+ #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+- pages_per_node = HPAGE_PMD_NR;
++ pages_per_block = HPAGE_PMD_NR;
+ #else
+ /* default to 2MB */
+- pages_per_node = 2UL << (20UL - PAGE_SHIFT);
++ pages_per_block = 2UL << (20UL - PAGE_SHIFT);
+ #endif
+- pages_per_node = max_t(uint32_t, pages_per_node,
+- tbo->page_alignment);
+- num_nodes = DIV_ROUND_UP_ULL(PFN_UP(mem_bytes), pages_per_node);
++ pages_per_block = max_t(uint32_t, pages_per_block,
++ tbo->page_alignment);
+ }
+
+- node = kvmalloc(struct_size(node, mm_nodes, num_nodes),
+- GFP_KERNEL | __GFP_ZERO);
+- if (!node)
++ vres = kzalloc(sizeof(*vres), GFP_KERNEL);
++ if (!vres)
+ return -ENOMEM;
+
+- ttm_resource_init(tbo, place, &node->base);
++ ttm_resource_init(tbo, place, &vres->base);
+
+ /* bail out quickly if there's likely not enough VRAM for this BO */
+ if (ttm_resource_manager_usage(man) > max_bytes) {
+@@ -415,66 +401,130 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
+ goto error_fini;
+ }
+
+- mode = DRM_MM_INSERT_BEST;
++ INIT_LIST_HEAD(&vres->blocks);
++
+ if (place->flags & TTM_PL_FLAG_TOPDOWN)
+- mode = DRM_MM_INSERT_HIGH;
+-
+- pages_left = node->base.num_pages;
+-
+- /* Limit maximum size to 2GB due to SG table limitations */
+- pages = min(pages_left, 2UL << (30 - PAGE_SHIFT));
+-
+- i = 0;
+- spin_lock(&mgr->lock);
+- while (pages_left) {
+- uint32_t alignment = tbo->page_alignment;
+-
+- if (pages >= pages_per_node)
+- alignment = pages_per_node;
+-
+- r = drm_mm_insert_node_in_range(mm, &node->mm_nodes[i], pages,
+- alignment, 0, place->fpfn,
+- lpfn, mode);
+- if (unlikely(r)) {
+- if (pages > pages_per_node) {
+- if (is_power_of_2(pages))
+- pages = pages / 2;
+- else
+- pages = rounddown_pow_of_two(pages);
+- continue;
++ vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
++
++ if (fpfn || lpfn != man->size)
++ /* Allocate blocks in desired range */
++ vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
++
++ remaining_size = vres->base.num_pages << PAGE_SHIFT;
++
++ mutex_lock(&mgr->lock);
++ while (remaining_size) {
++ if (tbo->page_alignment)
++ min_block_size = tbo->page_alignment << PAGE_SHIFT;
++ else
++ min_block_size = mgr->default_page_size;
++
++ BUG_ON(min_block_size < mm->chunk_size);
++
++ /* Limit maximum size to 2GiB due to SG table limitations */
++ size = min(remaining_size, 2ULL << 30);
++
++ if (size >= pages_per_block << PAGE_SHIFT)
++ min_block_size = pages_per_block << PAGE_SHIFT;
++
++ cur_size = size;
++
++ if (fpfn + size != place->lpfn << PAGE_SHIFT) {
++ /*
++ * Except for actual range allocation, modify the size and
++ * min_block_size conforming to continuous flag enablement
++ */
++ if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
++ size = roundup_pow_of_two(size);
++ min_block_size = size;
++ /*
++ * Modify the size value if size is not
++ * aligned with min_block_size
++ */
++ } else if (!IS_ALIGNED(size, min_block_size)) {
++ size = round_up(size, min_block_size);
+ }
+- goto error_free;
+ }
+
+- vis_usage += amdgpu_vram_mgr_vis_size(adev, &node->mm_nodes[i]);
+- amdgpu_vram_mgr_virt_start(&node->base, &node->mm_nodes[i]);
+- pages_left -= pages;
+- ++i;
++ r = drm_buddy_alloc_blocks(mm, fpfn,
++ lpfn,
++ size,
++ min_block_size,
++ &vres->blocks,
++ vres->flags);
++ if (unlikely(r))
++ goto error_free_blocks;
++
++ if (size > remaining_size)
++ remaining_size = 0;
++ else
++ remaining_size -= size;
++ }
++ mutex_unlock(&mgr->lock);
++
++ if (cur_size != size) {
++ struct drm_buddy_block *block;
++ struct list_head *trim_list;
++ u64 original_size;
++ LIST_HEAD(temp);
++
++ trim_list = &vres->blocks;
++ original_size = vres->base.num_pages << PAGE_SHIFT;
++
++ /*
++ * If size value is rounded up to min_block_size, trim the last
++ * block to the required size
++ */
++ if (!list_is_singular(&vres->blocks)) {
++ block = list_last_entry(&vres->blocks, typeof(*block), link);
++ list_move_tail(&block->link, &temp);
++ trim_list = &temp;
++ /*
++ * Compute the original_size value by subtracting the
++ * last block size with (aligned size - original size)
++ */
++ original_size = amdgpu_vram_mgr_block_size(block) - (size - cur_size);
++ }
+
+- if (pages > pages_left)
+- pages = pages_left;
++ mutex_lock(&mgr->lock);
++ drm_buddy_block_trim(mm,
++ original_size,
++ trim_list);
++ mutex_unlock(&mgr->lock);
++
++ if (!list_empty(&temp))
++ list_splice_tail(trim_list, &vres->blocks);
++ }
++
++ list_for_each_entry(block, &vres->blocks, link)
++ vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
++
++ block = amdgpu_vram_mgr_first_block(&vres->blocks);
++ if (!block) {
++ r = -EINVAL;
++ goto error_fini;
+ }
+- spin_unlock(&mgr->lock);
+
+- if (i == 1)
+- node->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
++ vres->base.start = amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT;
++
++ if (amdgpu_is_vram_mgr_blocks_contiguous(&vres->blocks))
++ vres->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
+
+ if (adev->gmc.xgmi.connected_to_cpu)
+- node->base.bus.caching = ttm_cached;
++ vres->base.bus.caching = ttm_cached;
+ else
+- node->base.bus.caching = ttm_write_combined;
++ vres->base.bus.caching = ttm_write_combined;
+
+ atomic64_add(vis_usage, &mgr->vis_usage);
+- *res = &node->base;
++ *res = &vres->base;
+ return 0;
+
+-error_free:
+- while (i--)
+- drm_mm_remove_node(&node->mm_nodes[i]);
+- spin_unlock(&mgr->lock);
++error_free_blocks:
++ drm_buddy_free_list(mm, &vres->blocks);
++ mutex_unlock(&mgr->lock);
+ error_fini:
+- ttm_resource_fini(man, &node->base);
+- kvfree(node);
++ ttm_resource_fini(man, &vres->base);
++ kfree(vres);
+
+ return r;
+ }
+@@ -490,27 +540,26 @@ error_fini:
+ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
+ struct ttm_resource *res)
+ {
+- struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
++ struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
+ struct amdgpu_device *adev = to_amdgpu_device(mgr);
++ struct drm_buddy *mm = &mgr->mm;
++ struct drm_buddy_block *block;
+ uint64_t vis_usage = 0;
+- unsigned i, pages;
+
+- spin_lock(&mgr->lock);
+- for (i = 0, pages = res->num_pages; pages;
+- pages -= node->mm_nodes[i].size, ++i) {
+- struct drm_mm_node *mm = &node->mm_nodes[i];
++ mutex_lock(&mgr->lock);
++ list_for_each_entry(block, &vres->blocks, link)
++ vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
+
+- drm_mm_remove_node(mm);
+- vis_usage += amdgpu_vram_mgr_vis_size(adev, mm);
+- }
+ amdgpu_vram_mgr_do_reserve(man);
+- spin_unlock(&mgr->lock);
++
++ drm_buddy_free_list(mm, &vres->blocks);
++ mutex_unlock(&mgr->lock);
+
+ atomic64_sub(vis_usage, &mgr->vis_usage);
+
+ ttm_resource_fini(man, res);
+- kvfree(node);
++ kfree(vres);
+ }
+
+ /**
+@@ -542,7 +591,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
+ if (!*sgt)
+ return -ENOMEM;
+
+- /* Determine the number of DRM_MM nodes to export */
++ /* Determine the number of DRM_BUDDY blocks to export */
+ amdgpu_res_first(res, offset, length, &cursor);
+ while (cursor.remaining) {
+ num_entries++;
+@@ -558,10 +607,10 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
+ sg->length = 0;
+
+ /*
+- * Walk down DRM_MM nodes to populate scatterlist nodes
+- * @note: Use iterator api to get first the DRM_MM node
++ * Walk down DRM_BUDDY blocks to populate scatterlist nodes
++ * @note: Use iterator api to get first the DRM_BUDDY block
+ * and the number of bytes from it. Access the following
+- * DRM_MM node(s) if more buffer needs to exported
++ * DRM_BUDDY block(s) if more buffer needs to exported
+ */
+ amdgpu_res_first(res, offset, length, &cursor);
+ for_each_sgtable_sg((*sgt), sg, i) {
+@@ -648,13 +697,22 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
+ struct drm_printer *printer)
+ {
+ struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
++ struct drm_buddy *mm = &mgr->mm;
++ struct drm_buddy_block *block;
+
+ drm_printf(printer, " vis usage:%llu\n",
+ amdgpu_vram_mgr_vis_usage(mgr));
+
+- spin_lock(&mgr->lock);
+- drm_mm_print(&mgr->mm, printer);
+- spin_unlock(&mgr->lock);
++ mutex_lock(&mgr->lock);
++ drm_printf(printer, "default_page_size: %lluKiB\n",
++ mgr->default_page_size >> 10);
++
++ drm_buddy_print(mm, printer);
++
++ drm_printf(printer, "reserved:\n");
++ list_for_each_entry(block, &mgr->reserved_pages, link)
++ drm_buddy_block_print(mm, block, printer);
++ mutex_unlock(&mgr->lock);
+ }
+
+ static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
+@@ -674,16 +732,21 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
+ {
+ struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
+ struct ttm_resource_manager *man = &mgr->manager;
++ int err;
+
+ ttm_resource_manager_init(man, &adev->mman.bdev,
+ adev->gmc.real_vram_size);
+
+ man->func = &amdgpu_vram_mgr_func;
+
+- drm_mm_init(&mgr->mm, 0, man->size >> PAGE_SHIFT);
+- spin_lock_init(&mgr->lock);
++ err = drm_buddy_init(&mgr->mm, man->size, PAGE_SIZE);
++ if (err)
++ return err;
++
++ mutex_init(&mgr->lock);
+ INIT_LIST_HEAD(&mgr->reservations_pending);
+ INIT_LIST_HEAD(&mgr->reserved_pages);
++ mgr->default_page_size = PAGE_SIZE;
+
+ ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
+ ttm_resource_manager_set_used(man, true);
+@@ -711,16 +774,16 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
+ if (ret)
+ return;
+
+- spin_lock(&mgr->lock);
+- list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node)
++ mutex_lock(&mgr->lock);
++ list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks)
+ kfree(rsv);
+
+- list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, node) {
+- drm_mm_remove_node(&rsv->mm_node);
++ list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
++ drm_buddy_free_list(&mgr->mm, &rsv->blocks);
+ kfree(rsv);
+ }
+- drm_mm_takedown(&mgr->mm);
+- spin_unlock(&mgr->lock);
++ drm_buddy_fini(&mgr->mm);
++ mutex_unlock(&mgr->lock);
+
+ ttm_resource_manager_cleanup(man);
+ ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+new file mode 100644
+index 000000000000..9a2db87186c7
+--- /dev/null
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+@@ -0,0 +1,89 @@
++/* SPDX-License-Identifier: MIT
++ * Copyright 2021 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ */
++
++#ifndef __AMDGPU_VRAM_MGR_H__
++#define __AMDGPU_VRAM_MGR_H__
++
++#include <drm/drm_buddy.h>
++
++struct amdgpu_vram_mgr {
++ struct ttm_resource_manager manager;
++ struct drm_buddy mm;
++ /* protects access to buffer objects */
++ struct mutex lock;
++ struct list_head reservations_pending;
++ struct list_head reserved_pages;
++ atomic64_t vis_usage;
++ u64 default_page_size;
++};
++
++struct amdgpu_vram_mgr_resource {
++ struct ttm_resource base;
++ struct list_head blocks;
++ unsigned long flags;
++};
++
++static inline u64 amdgpu_vram_mgr_block_start(struct drm_buddy_block *block)
++{
++ return drm_buddy_block_offset(block);
++}
++
++static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block)
++{
++ return PAGE_SIZE << drm_buddy_block_order(block);
++}
++
++static inline struct drm_buddy_block *
++amdgpu_vram_mgr_first_block(struct list_head *list)
++{
++ return list_first_entry_or_null(list, struct drm_buddy_block, link);
++}
++
++static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head)
++{
++ struct drm_buddy_block *block;
++ u64 start, size;
++
++ block = amdgpu_vram_mgr_first_block(head);
++ if (!block)
++ return false;
++
++ while (head != block->link.next) {
++ start = amdgpu_vram_mgr_block_start(block);
++ size = amdgpu_vram_mgr_block_size(block);
++
++ block = list_entry(block->link.next, struct drm_buddy_block, link);
++ if (start + size != amdgpu_vram_mgr_block_start(block))
++ return false;
++ }
++
++ return true;
++}
++
++static inline struct amdgpu_vram_mgr_resource *
++to_amdgpu_vram_mgr_resource(struct ttm_resource *res)
++{
++ return container_of(res, struct amdgpu_vram_mgr_resource, base);
++}
++
++#endif
+--
+cgit v1.2.1
+
+From 708d19d9f362766147cab79eccae60912c6d3068 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com>
+Date: Tue, 10 May 2022 13:26:46 +0200
+Subject: drm/amdgpu: move internal vram_mgr function into the C file
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+No need to have those in the header.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220510113649.879821-2-christian.koenig@amd.com
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 29 ++++++++++++++++++++++++++++
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 27 --------------------------
+ 2 files changed, 29 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+index 51d9d3a4456c..7a5e8a7b4a1b 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+@@ -50,6 +50,35 @@ to_amdgpu_device(struct amdgpu_vram_mgr *mgr)
+ return container_of(mgr, struct amdgpu_device, mman.vram_mgr);
+ }
+
++static inline struct drm_buddy_block *
++amdgpu_vram_mgr_first_block(struct list_head *list)
++{
++ return list_first_entry_or_null(list, struct drm_buddy_block, link);
++}
++
++static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head)
++{
++ struct drm_buddy_block *block;
++ u64 start, size;
++
++ block = amdgpu_vram_mgr_first_block(head);
++ if (!block)
++ return false;
++
++ while (head != block->link.next) {
++ start = amdgpu_vram_mgr_block_start(block);
++ size = amdgpu_vram_mgr_block_size(block);
++
++ block = list_entry(block->link.next, struct drm_buddy_block, link);
++ if (start + size != amdgpu_vram_mgr_block_start(block))
++ return false;
++ }
++
++ return true;
++}
++
++
++
+ /**
+ * DOC: mem_info_vram_total
+ *
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+index 9a2db87186c7..4b267bf1c5db 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+@@ -53,33 +53,6 @@ static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block)
+ return PAGE_SIZE << drm_buddy_block_order(block);
+ }
+
+-static inline struct drm_buddy_block *
+-amdgpu_vram_mgr_first_block(struct list_head *list)
+-{
+- return list_first_entry_or_null(list, struct drm_buddy_block, link);
+-}
+-
+-static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head)
+-{
+- struct drm_buddy_block *block;
+- u64 start, size;
+-
+- block = amdgpu_vram_mgr_first_block(head);
+- if (!block)
+- return false;
+-
+- while (head != block->link.next) {
+- start = amdgpu_vram_mgr_block_start(block);
+- size = amdgpu_vram_mgr_block_size(block);
+-
+- block = list_entry(block->link.next, struct drm_buddy_block, link);
+- if (start + size != amdgpu_vram_mgr_block_start(block))
+- return false;
+- }
+-
+- return true;
+-}
+-
+ static inline struct amdgpu_vram_mgr_resource *
+ to_amdgpu_vram_mgr_resource(struct ttm_resource *res)
+ {
+--
+cgit v1.2.1
+
+From 5e3f1e7729ec7a99e145e9d8ed58963d86cdfb98 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com>
+Date: Tue, 10 May 2022 12:52:05 +0200
+Subject: drm/amdgpu: fix start calculation in amdgpu_vram_mgr_new
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We still need to calculate a virtual start address for the resource to
+aid checking of it is visible or not. Only matters on small BAR systems,
+but better save than sorry.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220510113649.879821-1-christian.koenig@amd.com
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+index 49e4092f447f..51d9d3a4456c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+@@ -496,16 +496,22 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
+ list_splice_tail(trim_list, &vres->blocks);
+ }
+
+- list_for_each_entry(block, &vres->blocks, link)
+- vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
++ vres->base.start = 0;
++ list_for_each_entry(block, &vres->blocks, link) {
++ unsigned long start;
+
+- block = amdgpu_vram_mgr_first_block(&vres->blocks);
+- if (!block) {
+- r = -EINVAL;
+- goto error_fini;
+- }
++ start = amdgpu_vram_mgr_block_start(block) +
++ amdgpu_vram_mgr_block_size(block);
++ start >>= PAGE_SHIFT;
+
+- vres->base.start = amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT;
++ if (start > vres->base.num_pages)
++ start -= vres->base.num_pages;
++ else
++ start = 0;
++ vres->base.start = max(vres->base.start, start);
++
++ vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
++ }
+
+ if (amdgpu_is_vram_mgr_blocks_contiguous(&vres->blocks))
+ vres->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
+--
+cgit v1.2.1
+
+From 6f2c8d5f16594a13295d153245e0bb8166db7ac9 Mon Sep 17 00:00:00 2001
+From: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
+Date: Thu, 14 Jul 2022 03:12:14 -0700
+Subject: drm/amdgpu: Fix for drm buddy memory corruption
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+User reported gpu page fault when running graphics applications
+and in some cases garbaged graphics are observed as soon as X
+starts. This patch fixes all the issues.
+
+Fixed the typecast issue for fpfn and lpfn variables, thus
+preventing the overflow problem which resolves the memory
+corruption.
+
+Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
+Reported-by: Mike Lothian <mike@fireburn.co.uk>
+Tested-by: Mike Lothian <mike@fireburn.co.uk>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220714101214.7620-1-Arunpravin.PaneerSelvam@amd.com
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Christian König <christian.koenig@amd.com>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 16 ++++++++--------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h | 2 +-
+ 2 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+index 7a5e8a7b4a1b..28ec5f8ac1c1 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+@@ -395,11 +395,11 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
+ unsigned long pages_per_block;
+ int r;
+
+- lpfn = place->lpfn << PAGE_SHIFT;
++ lpfn = (u64)place->lpfn << PAGE_SHIFT;
+ if (!lpfn)
+ lpfn = man->size;
+
+- fpfn = place->fpfn << PAGE_SHIFT;
++ fpfn = (u64)place->fpfn << PAGE_SHIFT;
+
+ max_bytes = adev->gmc.mc_vram_size;
+ if (tbo->type != ttm_bo_type_kernel)
+@@ -439,12 +439,12 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
+ /* Allocate blocks in desired range */
+ vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
+
+- remaining_size = vres->base.num_pages << PAGE_SHIFT;
++ remaining_size = (u64)vres->base.num_pages << PAGE_SHIFT;
+
+ mutex_lock(&mgr->lock);
+ while (remaining_size) {
+ if (tbo->page_alignment)
+- min_block_size = tbo->page_alignment << PAGE_SHIFT;
++ min_block_size = (u64)tbo->page_alignment << PAGE_SHIFT;
+ else
+ min_block_size = mgr->default_page_size;
+
+@@ -453,12 +453,12 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
+ /* Limit maximum size to 2GiB due to SG table limitations */
+ size = min(remaining_size, 2ULL << 30);
+
+- if (size >= pages_per_block << PAGE_SHIFT)
+- min_block_size = pages_per_block << PAGE_SHIFT;
++ if (size >= (u64)pages_per_block << PAGE_SHIFT)
++ min_block_size = (u64)pages_per_block << PAGE_SHIFT;
+
+ cur_size = size;
+
+- if (fpfn + size != place->lpfn << PAGE_SHIFT) {
++ if (fpfn + size != (u64)place->lpfn << PAGE_SHIFT) {
+ /*
+ * Except for actual range allocation, modify the size and
+ * min_block_size conforming to continuous flag enablement
+@@ -498,7 +498,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
+ LIST_HEAD(temp);
+
+ trim_list = &vres->blocks;
+- original_size = vres->base.num_pages << PAGE_SHIFT;
++ original_size = (u64)vres->base.num_pages << PAGE_SHIFT;
+
+ /*
+ * If size value is rounded up to min_block_size, trim the last
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+index 4b267bf1c5db..0e04e42cf809 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
+@@ -50,7 +50,7 @@ static inline u64 amdgpu_vram_mgr_block_start(struct drm_buddy_block *block)
+
+ static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block)
+ {
+- return PAGE_SIZE << drm_buddy_block_order(block);
++ return (u64)PAGE_SIZE << drm_buddy_block_order(block);
+ }
+
+ static inline struct amdgpu_vram_mgr_resource *
+--
+cgit v1.2.1
+
diff --git a/SOURCES/asus-linux.patch b/SOURCES/asus-linux.patch
new file mode 100644
index 0000000..91e726d
--- /dev/null
+++ b/SOURCES/asus-linux.patch
@@ -0,0 +1,2509 @@
+From 00eccdc62138a9857c53533701745fee2d5cf4ff Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sun, 28 Aug 2022 19:44:46 +1200
+Subject: [PATCH] asus-wmi: Increase FAN_CURVE_BUF_LEN to 32
+
+Fix for TUF laptops returning with an -ENOSPC on calling
+asus_wmi_evaluate_method_buf() when fetching default curves. The TUF method
+requires at least 32 bytes space.
+
+This also moves and changes the pr_debug() in fan_curve_check_present() to
+pr_warn() in fan_curve_get_factory_default() so that there is at least some
+indication in logs of why it fails.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-wmi.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 3d9fd58573f9..11203213e00d 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -108,7 +108,7 @@ module_param(fnlock_default, bool, 0444);
+ #define WMI_EVENT_MASK 0xFFFF
+
+ #define FAN_CURVE_POINTS 8
+-#define FAN_CURVE_BUF_LEN (FAN_CURVE_POINTS * 2)
++#define FAN_CURVE_BUF_LEN 32
+ #define FAN_CURVE_DEV_CPU 0x00
+ #define FAN_CURVE_DEV_GPU 0x01
+ /* Mask to determine if setting temperature or percentage */
+@@ -2383,8 +2383,10 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)
+ curves = &asus->custom_fan_curves[fan_idx];
+ err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf,
+ FAN_CURVE_BUF_LEN);
+- if (err)
++ if (err) {
++ pr_warn("%s (0x%08x) failed: %d\n", __func__, fan_dev, err);
+ return err;
++ }
+
+ fan_curve_copy_from_buf(curves, buf);
+ curves->device_id = fan_dev;
+@@ -2402,9 +2404,6 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available,
+
+ err = fan_curve_get_factory_default(asus, fan_dev);
+ if (err) {
+- pr_debug("fan_curve_get_factory_default(0x%08x) failed: %d\n",
+- fan_dev, err);
+- /* Don't cause probe to fail on devices without fan-curves */
+ return 0;
+ }
+
+--
+2.37.2
+
+From e6529e0ad6942bb0eadc5f5ad0590124153e0a8c Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Wed, 3 Aug 2022 11:02:05 +1200
+Subject: [PATCH 1/1] HID: amd_sfh: Add keyguard for ASUS ROG X13 tablet
+
+Add support for ROG X13 Flow 2-in-1 to disable the keyboard when
+the lid is flipped.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 7 ++++-
+ drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 1 +
+ .../hid_descriptor/amd_sfh_hid_desc.c | 27 +++++++++++++++++++
+ .../hid_descriptor/amd_sfh_hid_desc.h | 9 +++++++
+ .../hid_descriptor/amd_sfh_hid_report_desc.h | 19 +++++++++++++
+ 5 files changed, 62 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+index dadc491bbf6b..243541d426d8 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+@@ -26,6 +26,7 @@
+ #define ACEL_EN BIT(0)
+ #define GYRO_EN BIT(1)
+ #define MAGNO_EN BIT(2)
++#define KBGUARD_EN BIT(15)
+ #define HPD_EN BIT(16)
+ #define ALS_EN BIT(19)
+
+@@ -232,6 +233,9 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
+ if (HPD_EN & activestatus)
+ sensor_id[num_of_sensors++] = HPD_IDX;
+
++ if (KBGUARD_EN & activestatus)
++ sensor_id[num_of_sensors++] = KBGUARD_IDX;
++
+ return num_of_sensors;
+ }
+
+@@ -373,7 +377,8 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_idx[i] != HPD_IDX &&
+- cl_data->sensor_sts[i] == SENSOR_ENABLED) {
++ cl_data->sensor_idx[i] != KBGUARD_IDX &&
++ cl_data->sensor_sts[i] == SENSOR_ENABLED) {
+ mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
+ status = amd_sfh_wait_for_response
+ (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+index 8c760526132a..4a86bc6038a2 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+@@ -36,6 +36,7 @@
+ #define SENSOR_DISABLED 5
+
+ #define HPD_IDX 16
++#define KBGUARD_IDX 15
+
+ #define AMD_SFH_IDLE_LOOP 200
+
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+index 76095bd53c65..f41d28ea7b93 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+@@ -57,6 +57,11 @@ int get_report_descriptor(int sensor_idx, u8 *rep_desc)
+ memcpy(rep_desc, hpd_report_descriptor,
+ sizeof(hpd_report_descriptor));
+ break;
++ case KBGUARD_IDX: /* kbguard ? */
++ memset(rep_desc, 0, sizeof(kbguard_report_descriptor));
++ memcpy(rep_desc, kbguard_report_descriptor,
++ sizeof(kbguard_report_descriptor));
++ break;
+ default:
+ break;
+ }
+@@ -116,6 +121,16 @@ u32 get_descr_sz(int sensor_idx, int descriptor_name)
+ return sizeof(struct hpd_feature_report);
+ }
+ break;
++ case KBGUARD_IDX:
++ switch (descriptor_name) {
++ case descr_size:
++ return sizeof(kbguard_report_descriptor);
++ case input_size:
++ return sizeof(struct kbguard_input_report);
++ case feature_size:
++ return sizeof(struct kbguard_feature_report);
++ }
++ break;
+
+ default:
+ break;
+@@ -139,6 +154,7 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+ struct gyro_feature_report gyro_feature;
+ struct magno_feature_report magno_feature;
+ struct hpd_feature_report hpd_feature;
++ struct kbguard_feature_report kbguard_feature;
+ struct als_feature_report als_feature;
+ u8 report_size = 0;
+
+@@ -186,6 +202,11 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+ memcpy(feature_report, &hpd_feature, sizeof(hpd_feature));
+ report_size = sizeof(hpd_feature);
+ break;
++ case KBGUARD_IDX: /* auto disable keyboard when flip out */
++ get_common_features(&kbguard_feature.common_property, report_id);
++ memcpy(feature_report, &kbguard_feature, sizeof(kbguard_feature));
++ report_size = sizeof(kbguard_feature);
++ break;
+
+ default:
+ break;
+@@ -210,6 +231,7 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_
+ struct accel3_input_report acc_input;
+ struct gyro_input_report gyro_input;
+ struct hpd_input_report hpd_input;
++ struct kbguard_input_report kbguard_input;
+ struct als_input_report als_input;
+ struct hpd_status hpdstatus;
+ u8 report_size = 0;
+@@ -262,6 +284,11 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_
+ report_size = sizeof(hpd_input);
+ memcpy(input_report, &hpd_input, sizeof(hpd_input));
+ break;
++ case KBGUARD_IDX: /* kb guard */
++ get_common_inputs(&kbguard_input.common_property, report_id);
++ report_size = sizeof(kbguard_input);
++ memcpy(input_report, &kbguard_input, sizeof(kbguard_input));
++break;
+ default:
+ break;
+ }
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+index 70b1b7abe2c6..98571a8597b3 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+@@ -105,12 +105,21 @@ struct hpd_feature_report {
+ struct common_feature_property common_property;
+ } __packed;
+
++struct kbguard_feature_report {
++ struct common_feature_property common_property;
++} __packed;
++
+ struct hpd_input_report {
+ struct common_input_property common_property;
+ /* values specific to human presence sensor */
+ u8 human_presence;
+ } __packed;
+
++struct kbguard_input_report {
++ struct common_input_property common_property;
++} __packed;
++
++
+ int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
+ u32 get_descr_sz(int sensor_idx, int descriptor_name);
+ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report);
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+index 697f2791ea9c..7a62fcec2c73 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+@@ -644,6 +644,25 @@ static const u8 als_report_descriptor[] = {
+ 0xC0 /* HID end collection */
+ };
+
++
++static const u8 kbguard_report_descriptor[] = {
++0x06, 0x43, 0xFF, // Usage Page (Vendor Defined 0xFF43)
++0x0A, 0x02, 0x02, // Usage (0x0202)
++0xA1, 0x01, // Collection (Application)
++0x85, 0x11, // Report ID (17)
++0x15, 0x00, // Logical Minimum (0)
++0x25, 0x01, // Logical Maximum (1)
++0x35, 0x00, // Physical Minimum (0)
++0x45, 0x01, // Physical Maximum (1)
++0x65, 0x00, // Unit (None)
++0x55, 0x00, // Unit Exponent (0)
++0x75, 0x01, // Report Size (1)
++0x95, 0x98, // Report Count (-104)
++0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
++0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
++0xC1, 0x00, // End Collection
++};
++
+ /* BIOMETRIC PRESENCE*/
+ static const u8 hpd_report_descriptor[] = {
+ 0x05, 0x20, /* Usage page */
+--
+2.37.1
+
+From 170f0da25dac630dacb920d043fb20e12c287520 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Tue, 9 Aug 2022 14:50:53 +1200
+Subject: [PATCH 01/19] platform/x86: asus-wmi: Convert all attr-show to use
+ sysfs_emit
+
+This changes all *_show attributes in asus-wmi.c to use sysfs_emit()
+instead of the older method of writing to the output buffer manually.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Link: https://lore.kernel.org/r/20220809025054.1626339-6-luke@ljones.dev
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/platform/x86/asus-wmi.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 89b604e04d7f..b5c977d37bc1 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -771,7 +771,7 @@ static ssize_t charge_control_end_threshold_show(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+ {
+- return sprintf(buf, "%d\n", charge_end_threshold);
++ return sysfs_emit(buf, "%d\n", charge_end_threshold);
+ }
+
+ static DEVICE_ATTR_RW(charge_control_end_threshold);
+@@ -1819,7 +1819,7 @@ static ssize_t pwm1_show(struct device *dev,
+ value = -1;
+ }
+
+- return sprintf(buf, "%d\n", value);
++ return sysfs_emit(buf, "%d\n", value);
+ }
+
+ static ssize_t pwm1_store(struct device *dev,
+@@ -1879,7 +1879,7 @@ static ssize_t fan1_input_show(struct device *dev,
+ return -ENXIO;
+ }
+
+- return sprintf(buf, "%d\n", value < 0 ? -1 : value*100);
++ return sysfs_emit(buf, "%d\n", value < 0 ? -1 : value * 100);
+ }
+
+ static ssize_t pwm1_enable_show(struct device *dev,
+@@ -1897,7 +1897,7 @@ static ssize_t pwm1_enable_show(struct device *dev,
+ * in practice on X532FL at least (the bit is always 0) and there's
+ * also nothing in the DSDT to indicate that this behaviour exists.
+ */
+- return sprintf(buf, "%d\n", asus->fan_pwm_mode);
++ return sysfs_emit(buf, "%d\n", asus->fan_pwm_mode);
+ }
+
+ static ssize_t pwm1_enable_store(struct device *dev,
+@@ -1965,7 +1965,7 @@ static ssize_t fan1_label_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+ {
+- return sprintf(buf, "%s\n", ASUS_FAN_DESC);
++ return sysfs_emit(buf, "%s\n", ASUS_FAN_DESC);
+ }
+
+ static ssize_t asus_hwmon_temp1(struct device *dev,
+@@ -2158,7 +2158,7 @@ static ssize_t fan_boost_mode_show(struct device *dev,
+ {
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+- return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_boost_mode);
++ return sysfs_emit(buf, "%d\n", asus->fan_boost_mode);
+ }
+
+ static ssize_t fan_boost_mode_store(struct device *dev,
+@@ -2711,7 +2711,7 @@ static ssize_t throttle_thermal_policy_show(struct device *dev,
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ u8 mode = asus->throttle_thermal_policy_mode;
+
+- return scnprintf(buf, PAGE_SIZE, "%d\n", mode);
++ return sysfs_emit(buf, "%d\n", mode);
+ }
+
+ static ssize_t throttle_thermal_policy_store(struct device *dev,
+--
+2.37.2
+
+From a8f9c36c4bb705af4b6054244ff9669cdd8dcf71 Mon Sep 17 00:00:00 2001
+From: ye xingchen <ye.xingchen@zte.com.cn>
+Date: Thu, 11 Aug 2022 01:32:03 +0000
+Subject: [PATCH 02/19] platform/x86: asus-wmi: Use kobj_to_dev()
+
+Use kobj_to_dev() instead of open-coding it.
+
+Reported-by: Zeal Robot <zealci@zte.com.cn>
+Signed-off-by: ye xingchen <ye.xingchen@zte.com.cn>
+Link: https://lore.kernel.org/r/20220811013203.16010-1-ye.xingchen@zte.com.cn
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/platform/x86/asus-wmi.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index b5c977d37bc1..e461299d938a 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -2006,7 +2006,7 @@ static struct attribute *hwmon_attributes[] = {
+ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
+ struct attribute *attr, int idx)
+ {
+- struct device *dev = container_of(kobj, struct device, kobj);
++ struct device *dev = kobj_to_dev(kobj);
+ struct asus_wmi *asus = dev_get_drvdata(dev->parent);
+ u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
+
+@@ -3294,7 +3294,7 @@ static struct attribute *platform_attributes[] = {
+ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
+ struct attribute *attr, int idx)
+ {
+- struct device *dev = container_of(kobj, struct device, kobj);
++ struct device *dev = kobj_to_dev(kobj);
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ bool ok = true;
+ int devid = -1;
+--
+2.37.2
+
+From 7e64c486e807c8edfbd3a0c8e44ad7a1896dbec8 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 10:25:04 +1200
+Subject: [PATCH 03/19] platform/x86: asus-wmi: Document the dgpu_disable sysfs
+ attribute
+
+The dgpu_disable attribute was not documented, this adds the
+required documentation.
+
+Fixes: 98829e84dc67 ("asus-wmi: Add dgpu disable method")
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220812222509.292692-2-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/ABI/testing/sysfs-platform-asus-wmi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+index 04885738cf15..0f8f0772d6f3 100644
+--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+@@ -57,3 +57,12 @@ Description:
+ * 0 - default,
+ * 1 - overboost,
+ * 2 - silent
++
++What: /sys/devices/platform/<platform>/dgpu_disable
++Date: Aug 2022
++KernelVersion: 5.17
++Contact: "Luke Jones" <luke@ljones.dev>
++Description:
++ Disable discrete GPU:
++ * 0 - Enable dGPU,
++ * 1 - Disable dGPU
+--
+2.37.2
+
+From 3206376f099d9c74d9938b9c41cfc0b85ea6e1b0 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 10:25:05 +1200
+Subject: [PATCH 04/19] platform/x86: asus-wmi: Document the egpu_enable sysfs
+ attribute
+
+The egpu_enable attribute was not documented, this adds the
+required documentation.
+
+Fixes: 382b91db8044 ("asus-wmi: Add egpu enable method")
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220812222509.292692-3-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/ABI/testing/sysfs-platform-asus-wmi | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+index 0f8f0772d6f3..ac5ec3a17c51 100644
+--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+@@ -66,3 +66,14 @@ Description:
+ Disable discrete GPU:
+ * 0 - Enable dGPU,
+ * 1 - Disable dGPU
++
++What: /sys/devices/platform/<platform>/egpu_enable
++Date: Aug 2022
++KernelVersion: 5.17
++Contact: "Luke Jones" <luke@ljones.dev>
++Description:
++ Enable the external GPU paired with ROG X-Flow laptops.
++ Toggling this setting will also trigger ACPI to disable the dGPU:
++
++ * 0 - Disable,
++ * 1 - Enable
+--
+2.37.2
+
+From d956c889be804742e39fbb3291b054b3cbf505be Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 10:25:06 +1200
+Subject: [PATCH 05/19] platform/x86: asus-wmi: Document the panel_od sysfs
+ attribute
+
+The panel_od attribute was not documented, this adds the
+required documentation.
+
+Fixes: ca91ea34778f ("asus-wmi: Add panel overdrive functionality")
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220812222509.292692-4-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/ABI/testing/sysfs-platform-asus-wmi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+index ac5ec3a17c51..4d63824713ac 100644
+--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+@@ -77,3 +77,12 @@ Description:
+
+ * 0 - Disable,
+ * 1 - Enable
++
++What: /sys/devices/platform/<platform>/panel_od
++Date: Aug 2022
++KernelVersion: 5.17
++Contact: "Luke Jones" <luke@ljones.dev>
++Description:
++ Enable an LCD response-time boost to reduce or remove ghosting:
++ * 0 - Disable,
++ * 1 - Enable
+--
+2.37.2
+
+From cdf36fc865f0aff8de5a9afc3654f114c4d04cba Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 10:25:07 +1200
+Subject: [PATCH 06/19] platform/x86: asus-wmi: Refactor disable_gpu attribute
+
+The settings for these attributes can be read from the device, this
+is now done instead of reading a stored value from module. The stored
+value is also removed.
+
+This means the simpler asus_wmi_dev_is_present() can be used in
+*_check_present() - it is not an error for these methods to be
+missing.
+
+The _write() functions have their bodies shifted in to *_store()
+which simplifies things further.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220812222509.292692-5-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/platform/x86/asus-wmi.c | 73 +++++++++++----------------------
+ 1 file changed, 24 insertions(+), 49 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index e461299d938a..f58cbda862d2 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -233,7 +233,6 @@ struct asus_wmi {
+ bool egpu_enable;
+
+ bool dgpu_disable_available;
+- bool dgpu_disable;
+
+ bool throttle_thermal_policy_available;
+ u8 throttle_thermal_policy_mode;
+@@ -563,47 +562,10 @@ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
+ /* dGPU ********************************************************************/
+ static int dgpu_disable_check_present(struct asus_wmi *asus)
+ {
+- u32 result;
+- int err;
+-
+ asus->dgpu_disable_available = false;
+
+- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_DGPU, &result);
+- if (err) {
+- if (err == -ENODEV)
+- return 0;
+- return err;
+- }
+-
+- if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
++ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU))
+ asus->dgpu_disable_available = true;
+- asus->dgpu_disable = result & ASUS_WMI_DSTS_STATUS_BIT;
+- }
+-
+- return 0;
+-}
+-
+-static int dgpu_disable_write(struct asus_wmi *asus)
+-{
+- u32 retval;
+- u8 value;
+- int err;
+-
+- /* Don't rely on type conversion */
+- value = asus->dgpu_disable ? 1 : 0;
+-
+- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, value, &retval);
+- if (err) {
+- pr_warn("Failed to set dgpu disable: %d\n", err);
+- return err;
+- }
+-
+- if (retval > 1) {
+- pr_warn("Failed to set dgpu disable (retval): 0x%x\n", retval);
+- return -EIO;
+- }
+-
+- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "dgpu_disable");
+
+ return 0;
+ }
+@@ -612,9 +574,13 @@ static ssize_t dgpu_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+- u8 mode = asus->dgpu_disable;
++ int result;
+
+- return sysfs_emit(buf, "%d\n", mode);
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU);
++ if (result < 0)
++ return result;
++
++ return sysfs_emit(buf, "%d\n", result);
+ }
+
+ /*
+@@ -627,24 +593,33 @@ static ssize_t dgpu_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+- bool disable;
+- int result;
++ int result, err;
++ u32 disable;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+- result = kstrtobool(buf, &disable);
++ result = kstrtou32(buf, 10, &disable);
+ if (result)
+ return result;
+
+- asus->dgpu_disable = disable;
++ if (disable > 1)
++ return -EINVAL;
+
+- result = dgpu_disable_write(asus);
+- if (result)
+- return result;
++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
++ if (err) {
++ pr_warn("Failed to set dgpu disable: %d\n", err);
++ return err;
++ }
++
++ if (result > 1) {
++ pr_warn("Failed to set dgpu disable (result): 0x%x\n", result);
++ return -EIO;
++ }
++
++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "dgpu_disable");
+
+ return count;
+ }
+-
+ static DEVICE_ATTR_RW(dgpu_disable);
+
+ /* eGPU ********************************************************************/
+--
+2.37.2
+
+From 36450e7db0fe55c338f32059382a2d8342cbc9a1 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 10:25:08 +1200
+Subject: [PATCH 07/19] platform/x86: asus-wmi: Refactor egpu_enable attribute
+
+The settings for these attributes can be read from the device, this
+is now done instead of reading a stored value from module. The stored
+value is also removed.
+
+This means the simpler asus_wmi_dev_is_present() can be used in
+*_check_present() - it is not an error for these methods to be
+missing.
+
+The _write() functions have their bodies shifted in to *_store()
+which simplifies things further.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220812222509.292692-6-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/platform/x86/asus-wmi.c | 84 ++++++++++-----------------------
+ 1 file changed, 26 insertions(+), 58 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index f58cbda862d2..c82e7b128444 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -229,9 +229,7 @@ struct asus_wmi {
+ u8 fan_boost_mode_mask;
+ u8 fan_boost_mode;
+
+- bool egpu_enable_available; // 0 = enable
+- bool egpu_enable;
+-
++ bool egpu_enable_available;
+ bool dgpu_disable_available;
+
+ bool throttle_thermal_policy_available;
+@@ -625,48 +623,10 @@ static DEVICE_ATTR_RW(dgpu_disable);
+ /* eGPU ********************************************************************/
+ static int egpu_enable_check_present(struct asus_wmi *asus)
+ {
+- u32 result;
+- int err;
+-
+ asus->egpu_enable_available = false;
+
+- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_EGPU, &result);
+- if (err) {
+- if (err == -ENODEV)
+- return 0;
+- return err;
+- }
+-
+- if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
++ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU))
+ asus->egpu_enable_available = true;
+- asus->egpu_enable = result & ASUS_WMI_DSTS_STATUS_BIT;
+- }
+-
+- return 0;
+-}
+-
+-static int egpu_enable_write(struct asus_wmi *asus)
+-{
+- u32 retval;
+- u8 value;
+- int err;
+-
+- /* Don't rely on type conversion */
+- value = asus->egpu_enable ? 1 : 0;
+-
+- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, value, &retval);
+-
+- if (err) {
+- pr_warn("Failed to set egpu disable: %d\n", err);
+- return err;
+- }
+-
+- if (retval > 1) {
+- pr_warn("Failed to set egpu disable (retval): 0x%x\n", retval);
+- return -EIO;
+- }
+-
+- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable");
+
+ return 0;
+ }
+@@ -675,9 +635,13 @@ static ssize_t egpu_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+- bool mode = asus->egpu_enable;
++ int result;
+
+- return sysfs_emit(buf, "%d\n", mode);
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU);
++ if (result < 0)
++ return result;
++
++ return sysfs_emit(buf, "%d\n", result);
+ }
+
+ /* The ACPI call to enable the eGPU also disables the internal dGPU */
+@@ -685,29 +649,33 @@ static ssize_t egpu_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+- bool enable;
+- int result;
++ int result, err;
++ u32 enable;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+- result = kstrtobool(buf, &enable);
+- if (result)
+- return result;
++ err = kstrtou32(buf, 10, &enable);
++ if (err)
++ return err;
+
+- asus->egpu_enable = enable;
++ if (enable > 1)
++ return -EINVAL;
+
+- result = egpu_enable_write(asus);
+- if (result)
+- return result;
++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
++ if (err) {
++ pr_warn("Failed to set egpu disable: %d\n", err);
++ return err;
++ }
+
+- /* Ensure that the kernel status of dgpu is updated */
+- result = dgpu_disable_check_present(asus);
+- if (result)
+- return result;
++ if (result > 1) {
++ pr_warn("Failed to set egpu disable (retval): 0x%x\n", result);
++ return -EIO;
++ }
++
++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable");
+
+ return count;
+ }
+-
+ static DEVICE_ATTR_RW(egpu_enable);
+
+ /* Battery ********************************************************************/
+--
+2.37.2
+
+From ebc443ad379fad80b8fc350f35cc0652b8447995 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 10:25:09 +1200
+Subject: [PATCH 08/19] platform/x86: asus-wmi: Refactor panel_od attribute
+
+The settings for these attributes can be read from the device, this
+is now done instead of reading a stored value from module. The stored
+value is also removed.
+
+This means the simpler asus_wmi_dev_is_present() can be used in
+*_check_present() - it is not an error for these methods to be
+missing.
+
+The _write() functions have their bodies shifted in to *_store()
+which simplifies things further.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220812222509.292692-7-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/platform/x86/asus-wmi.c | 74 +++++++++++----------------------
+ 1 file changed, 25 insertions(+), 49 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index c82e7b128444..2d9d709aa59f 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -246,7 +246,6 @@ struct asus_wmi {
+ bool battery_rsoc_available;
+
+ bool panel_overdrive_available;
+- bool panel_overdrive;
+
+ struct hotplug_slot hotplug_slot;
+ struct mutex hotplug_lock;
+@@ -1500,48 +1499,10 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
+ /* Panel Overdrive ************************************************************/
+ static int panel_od_check_present(struct asus_wmi *asus)
+ {
+- u32 result;
+- int err;
+-
+ asus->panel_overdrive_available = false;
+
+- err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_PANEL_OD, &result);
+- if (err) {
+- if (err == -ENODEV)
+- return 0;
+- return err;
+- }
+-
+- if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
++ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD))
+ asus->panel_overdrive_available = true;
+- asus->panel_overdrive = result & ASUS_WMI_DSTS_STATUS_BIT;
+- }
+-
+- return 0;
+-}
+-
+-static int panel_od_write(struct asus_wmi *asus)
+-{
+- u32 retval;
+- u8 value;
+- int err;
+-
+- /* Don't rely on type conversion */
+- value = asus->panel_overdrive ? 1 : 0;
+-
+- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, value, &retval);
+-
+- if (err) {
+- pr_warn("Failed to set panel overdrive: %d\n", err);
+- return err;
+- }
+-
+- if (retval > 1) {
+- pr_warn("Failed to set panel overdrive (retval): 0x%x\n", retval);
+- return -EIO;
+- }
+-
+- sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od");
+
+ return 0;
+ }
+@@ -1550,32 +1511,47 @@ static ssize_t panel_od_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ struct asus_wmi *asus = dev_get_drvdata(dev);
++ int result;
+
+- return sysfs_emit(buf, "%d\n", asus->panel_overdrive);
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_PANEL_OD);
++ if (result < 0)
++ return result;
++
++ return sysfs_emit(buf, "%d\n", result);
+ }
+
+ static ssize_t panel_od_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+- bool overdrive;
+- int result;
++ int result, err;
++ u32 overdrive;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+- result = kstrtobool(buf, &overdrive);
++ result = kstrtou32(buf, 10, &overdrive);
+ if (result)
+ return result;
+
+- asus->panel_overdrive = overdrive;
+- result = panel_od_write(asus);
++ if (overdrive > 1)
++ return -EINVAL;
+
+- if (result)
+- return result;
++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, overdrive, &result);
++
++ if (err) {
++ pr_warn("Failed to set panel overdrive: %d\n", err);
++ return err;
++ }
++
++ if (result > 1) {
++ pr_warn("Failed to set panel overdrive (result): 0x%x\n", result);
++ return -EIO;
++ }
++
++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od");
+
+ return count;
+ }
+-
+ static DEVICE_ATTR_RW(panel_od);
+
+ /* Quirks *********************************************************************/
+--
+2.37.2
+
+From 3c3b55564afa8b7d952ce2ba90e7f522832ed0f7 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 15 Aug 2022 17:05:38 +0200
+Subject: [PATCH 09/19] platform/x86: asus-wmi: Simplify some of the
+ *_check_present() helpers
+
+After the recent cleanup patches, some of the *_check_present() helpers
+just propagate the result of asus_wmi_dev_is_present().
+
+Replace these with direct asus_wmi_dev_is_present() calls as a further
+cleanup.
+
+Cc: Luke D. Jones <luke@ljones.dev>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20220815150538.474306-1-hdegoede@redhat.com
+---
+ drivers/platform/x86/asus-wmi.c | 47 +++------------------------------
+ 1 file changed, 3 insertions(+), 44 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 2d9d709aa59f..d72491fb218b 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -557,16 +557,6 @@ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
+ }
+
+ /* dGPU ********************************************************************/
+-static int dgpu_disable_check_present(struct asus_wmi *asus)
+-{
+- asus->dgpu_disable_available = false;
+-
+- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU))
+- asus->dgpu_disable_available = true;
+-
+- return 0;
+-}
+-
+ static ssize_t dgpu_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+@@ -620,16 +610,6 @@ static ssize_t dgpu_disable_store(struct device *dev,
+ static DEVICE_ATTR_RW(dgpu_disable);
+
+ /* eGPU ********************************************************************/
+-static int egpu_enable_check_present(struct asus_wmi *asus)
+-{
+- asus->egpu_enable_available = false;
+-
+- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU))
+- asus->egpu_enable_available = true;
+-
+- return 0;
+-}
+-
+ static ssize_t egpu_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+@@ -1497,16 +1477,6 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
+ }
+
+ /* Panel Overdrive ************************************************************/
+-static int panel_od_check_present(struct asus_wmi *asus)
+-{
+- asus->panel_overdrive_available = false;
+-
+- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD))
+- asus->panel_overdrive_available = true;
+-
+- return 0;
+-}
+-
+ static ssize_t panel_od_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+@@ -3493,13 +3463,9 @@ static int asus_wmi_add(struct platform_device *pdev)
+ if (err)
+ goto fail_platform;
+
+- err = egpu_enable_check_present(asus);
+- if (err)
+- goto fail_egpu_enable;
+-
+- err = dgpu_disable_check_present(asus);
+- if (err)
+- goto fail_dgpu_disable;
++ asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
++ asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
++ asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
+
+ err = fan_boost_mode_check_present(asus);
+ if (err)
+@@ -3515,10 +3481,6 @@ static int asus_wmi_add(struct platform_device *pdev)
+ if (err)
+ goto fail_platform_profile_setup;
+
+- err = panel_od_check_present(asus);
+- if (err)
+- goto fail_panel_od;
+-
+ err = asus_wmi_sysfs_init(asus->platform_device);
+ if (err)
+ goto fail_sysfs;
+@@ -3613,10 +3575,7 @@ static int asus_wmi_add(struct platform_device *pdev)
+ if (asus->platform_profile_support)
+ platform_profile_remove();
+ fail_fan_boost_mode:
+-fail_egpu_enable:
+-fail_dgpu_disable:
+ fail_platform:
+-fail_panel_od:
+ kfree(asus);
+ return err;
+ }
+--
+2.37.2
+
+From 01ef026ab36357a818c7d8324a36dbb8beff6ff5 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 21:26:24 +1200
+Subject: [PATCH 10/19] platform/x86: asus-wmi: Support the hardware GPU MUX on
+ some laptops
+
+Support the hardware GPU MUX switch available on some models. This
+switch can toggle the MUX between:
+
+- 0, Dedicated mode
+- 1, Optimus mode
+
+Optimus mode is the regular iGPU + dGPU available, while dedicated
+mode switches the system to have only the dGPU available.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220813092624.6228-1-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../ABI/testing/sysfs-platform-asus-wmi | 12 +++++
+ drivers/platform/x86/asus-wmi.c | 51 +++++++++++++++++++
+ include/linux/platform_data/x86/asus-wmi.h | 3 ++
+ 3 files changed, 66 insertions(+)
+
+diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+index 4d63824713ac..a77a004a1baa 100644
+--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
+@@ -58,6 +58,18 @@ Description:
+ * 1 - overboost,
+ * 2 - silent
+
++What: /sys/devices/platform/<platform>/gpu_mux_mode
++Date: Aug 2022
++KernelVersion: 6.1
++Contact: "Luke Jones" <luke@ljones.dev>
++Description:
++ Switch the GPU hardware MUX mode. Laptops with this feature can
++ can be toggled to boot with only the dGPU (discrete mode) or in
++ standard Optimus/Hybrid mode. On switch a reboot is required:
++
++ * 0 - Discrete GPU,
++ * 1 - Optimus/Hybrid,
++
+ What: /sys/devices/platform/<platform>/dgpu_disable
+ Date: Aug 2022
+ KernelVersion: 5.17
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index d72491fb218b..46d0dd96a351 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -231,6 +231,7 @@ struct asus_wmi {
+
+ bool egpu_enable_available;
+ bool dgpu_disable_available;
++ bool gpu_mux_mode_available;
+
+ bool throttle_thermal_policy_available;
+ u8 throttle_thermal_policy_mode;
+@@ -657,6 +658,52 @@ static ssize_t egpu_enable_store(struct device *dev,
+ }
+ static DEVICE_ATTR_RW(egpu_enable);
+
++/* gpu mux switch *************************************************************/
++static ssize_t gpu_mux_mode_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct asus_wmi *asus = dev_get_drvdata(dev);
++ int result;
++
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
++ if (result < 0)
++ return result;
++
++ return sysfs_emit(buf, "%d\n", result);
++}
++
++static ssize_t gpu_mux_mode_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct asus_wmi *asus = dev_get_drvdata(dev);
++ int result, err;
++ u32 optimus;
++
++ err = kstrtou32(buf, 10, &optimus);
++ if (err)
++ return err;
++
++ if (optimus > 1)
++ return -EINVAL;
++
++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result);
++ if (err) {
++ dev_err(dev, "Failed to set GPU MUX mode: %d\n", err);
++ return err;
++ }
++ /* !1 is considered a fail by ASUS */
++ if (result != 1) {
++ dev_warn(dev, "Failed to set GPU MUX mode (result): 0x%x\n", result);
++ return -EIO;
++ }
++
++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "gpu_mux_mode");
++
++ return count;
++}
++static DEVICE_ATTR_RW(gpu_mux_mode);
++
+ /* Battery ********************************************************************/
+
+ /* The battery maximum charging percentage */
+@@ -3172,6 +3219,7 @@ static struct attribute *platform_attributes[] = {
+ &dev_attr_touchpad.attr,
+ &dev_attr_egpu_enable.attr,
+ &dev_attr_dgpu_disable.attr,
++ &dev_attr_gpu_mux_mode.attr,
+ &dev_attr_lid_resume.attr,
+ &dev_attr_als_enable.attr,
+ &dev_attr_fan_boost_mode.attr,
+@@ -3202,6 +3250,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
+ ok = asus->egpu_enable_available;
+ else if (attr == &dev_attr_dgpu_disable.attr)
+ ok = asus->dgpu_disable_available;
++ else if (attr == &dev_attr_gpu_mux_mode.attr)
++ ok = asus->gpu_mux_mode_available;
+ else if (attr == &dev_attr_fan_boost_mode.attr)
+ ok = asus->fan_boost_mode_available;
+ else if (attr == &dev_attr_throttle_thermal_policy.attr)
+@@ -3465,6 +3515,7 @@ static int asus_wmi_add(struct platform_device *pdev)
+
+ asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
+ asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
++ asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
+ asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
+
+ err = fan_boost_mode_check_present(asus);
+diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
+index 98f2b2f20f3e..70d2347bf6ca 100644
+--- a/include/linux/platform_data/x86/asus-wmi.h
++++ b/include/linux/platform_data/x86/asus-wmi.h
+@@ -99,6 +99,9 @@
+ /* dgpu on/off */
+ #define ASUS_WMI_DEVID_DGPU 0x00090020
+
++/* gpu mux switch, 0 = dGPU, 1 = Optimus */
++#define ASUS_WMI_DEVID_GPU_MUX 0x00090016
++
+ /* DSTS masks */
+ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
+ #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
+--
+2.37.2
+
+From 00aa846955fbfb04f7bc0c26c49febfe5395eca1 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 21:27:52 +1200
+Subject: [PATCH 11/19] platform/x86: asus-wmi: Adjust tablet/lidflip handling
+ to use enum
+
+Due to multiple types of tablet/lidflip, the existing code for
+handling these events is refactored to use an enum for each type.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220813092753.6635-1-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/platform/x86/asus-nb-wmi.c | 13 +++-----
+ drivers/platform/x86/asus-wmi.c | 49 +++++++++++++++++++++---------
+ drivers/platform/x86/asus-wmi.h | 9 ++++--
+ 3 files changed, 47 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
+index 478dd300b9c9..4672a2b8322e 100644
+--- a/drivers/platform/x86/asus-nb-wmi.c
++++ b/drivers/platform/x86/asus-nb-wmi.c
+@@ -115,12 +115,12 @@ static struct quirk_entry quirk_asus_forceals = {
+ };
+
+ static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
+- .use_kbd_dock_devid = true,
++ .tablet_switch_mode = asus_wmi_kbd_dock_devid,
+ };
+
+ static struct quirk_entry quirk_asus_use_lid_flip_devid = {
+ .wmi_backlight_set_devstate = true,
+- .use_lid_flip_devid = true,
++ .tablet_switch_mode = asus_wmi_lid_flip_devid,
+ };
+
+ static int dmi_matched(const struct dmi_system_id *dmi)
+@@ -492,16 +492,13 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
+
+ switch (tablet_mode_sw) {
+ case 0:
+- quirks->use_kbd_dock_devid = false;
+- quirks->use_lid_flip_devid = false;
++ quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
+ break;
+ case 1:
+- quirks->use_kbd_dock_devid = true;
+- quirks->use_lid_flip_devid = false;
++ quirks->tablet_switch_mode = asus_wmi_kbd_dock_devid;
+ break;
+ case 2:
+- quirks->use_kbd_dock_devid = false;
+- quirks->use_lid_flip_devid = true;
++ quirks->tablet_switch_mode = asus_wmi_lid_flip_devid;
+ break;
+ }
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 46d0dd96a351..fe2d072e1acc 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -486,8 +486,11 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
+
+ static int asus_wmi_input_init(struct asus_wmi *asus)
+ {
++ struct device *dev;
+ int err, result;
+
++ dev = &asus->platform_device->dev;
++
+ asus->inputdev = input_allocate_device();
+ if (!asus->inputdev)
+ return -ENOMEM;
+@@ -495,35 +498,38 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
+ asus->inputdev->name = asus->driver->input_name;
+ asus->inputdev->phys = asus->driver->input_phys;
+ asus->inputdev->id.bustype = BUS_HOST;
+- asus->inputdev->dev.parent = &asus->platform_device->dev;
++ asus->inputdev->dev.parent = dev;
+ set_bit(EV_REP, asus->inputdev->evbit);
+
+ err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
+ if (err)
+ goto err_free_dev;
+
+- if (asus->driver->quirks->use_kbd_dock_devid) {
++ switch (asus->driver->quirks->tablet_switch_mode) {
++ case asus_wmi_no_tablet_switch:
++ break;
++ case asus_wmi_kbd_dock_devid:
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
+ if (result >= 0) {
+ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+ input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
+ } else if (result != -ENODEV) {
+- pr_err("Error checking for keyboard-dock: %d\n", result);
++ dev_err(dev, "Error checking for keyboard-dock: %d\n", result);
+ }
+- }
+-
+- if (asus->driver->quirks->use_lid_flip_devid) {
++ break;
++ case asus_wmi_lid_flip_devid:
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
+ if (result < 0)
+- asus->driver->quirks->use_lid_flip_devid = 0;
++ asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
+ if (result >= 0) {
+ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+ input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+ } else if (result == -ENODEV) {
+- pr_err("This device has lid_flip quirk but got ENODEV checking it. This is a bug.");
++ dev_err(dev, "This device has lid_flip quirk but got ENODEV checking it. This is a bug.");
+ } else {
+- pr_err("Error checking for lid-flip: %d\n", result);
++ dev_err(dev, "Error checking for lid-flip: %d\n", result);
+ }
++ break;
+ }
+
+ err = input_register_device(asus->inputdev);
+@@ -549,8 +555,9 @@ static void asus_wmi_input_exit(struct asus_wmi *asus)
+
+ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
+ {
+- int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
++ int result;
+
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
+ if (result >= 0) {
+ input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+ input_sync(asus->inputdev);
+@@ -3044,7 +3051,8 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+ return;
+ }
+
+- if (asus->driver->quirks->use_kbd_dock_devid && code == NOTIFY_KBD_DOCK_CHANGE) {
++ if (asus->driver->quirks->tablet_switch_mode == asus_wmi_kbd_dock_devid &&
++ code == NOTIFY_KBD_DOCK_CHANGE) {
+ result = asus_wmi_get_devstate_simple(asus,
+ ASUS_WMI_DEVID_KBD_DOCK);
+ if (result >= 0) {
+@@ -3055,7 +3063,8 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+ return;
+ }
+
+- if (asus->driver->quirks->use_lid_flip_devid && code == NOTIFY_LID_FLIP) {
++ if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_devid &&
++ code == NOTIFY_LID_FLIP) {
+ lid_flip_tablet_mode_get_state(asus);
+ return;
+ }
+@@ -3685,8 +3694,14 @@ static int asus_hotk_resume(struct device *device)
+ if (asus_wmi_has_fnlock_key(asus))
+ asus_wmi_fnlock_update(asus);
+
+- if (asus->driver->quirks->use_lid_flip_devid)
++ switch (asus->driver->quirks->tablet_switch_mode) {
++ case asus_wmi_no_tablet_switch:
++ case asus_wmi_kbd_dock_devid:
++ break;
++ case asus_wmi_lid_flip_devid:
+ lid_flip_tablet_mode_get_state(asus);
++ break;
++ }
+
+ return 0;
+ }
+@@ -3727,8 +3742,14 @@ static int asus_hotk_restore(struct device *device)
+ if (asus_wmi_has_fnlock_key(asus))
+ asus_wmi_fnlock_update(asus);
+
+- if (asus->driver->quirks->use_lid_flip_devid)
++ switch (asus->driver->quirks->tablet_switch_mode) {
++ case asus_wmi_no_tablet_switch:
++ case asus_wmi_kbd_dock_devid:
++ break;
++ case asus_wmi_lid_flip_devid:
+ lid_flip_tablet_mode_get_state(asus);
++ break;
++ }
+
+ return 0;
+ }
+diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
+index b302415bf1d9..413920bad0c6 100644
+--- a/drivers/platform/x86/asus-wmi.h
++++ b/drivers/platform/x86/asus-wmi.h
+@@ -25,6 +25,12 @@ struct module;
+ struct key_entry;
+ struct asus_wmi;
+
++enum asus_wmi_tablet_switch_mode {
++ asus_wmi_no_tablet_switch,
++ asus_wmi_kbd_dock_devid,
++ asus_wmi_lid_flip_devid,
++};
++
+ struct quirk_entry {
+ bool hotplug_wireless;
+ bool scalar_panel_brightness;
+@@ -33,8 +39,7 @@ struct quirk_entry {
+ bool wmi_backlight_native;
+ bool wmi_backlight_set_devstate;
+ bool wmi_force_als_set;
+- bool use_kbd_dock_devid;
+- bool use_lid_flip_devid;
++ enum asus_wmi_tablet_switch_mode tablet_switch_mode;
+ int wapf;
+ /*
+ * For machines with AMD graphic chips, it will send out WMI event
+--
+2.37.2
+
+From e397c3c460bf3849384f2f55516d1887617cfca9 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Sat, 13 Aug 2022 21:27:53 +1200
+Subject: [PATCH 12/19] platform/x86: asus-wmi: Add support for ROG X13 tablet
+ mode
+
+Add quirk for ASUS ROG X13 Flow 2-in-1 to enable tablet mode with
+lid flip (all screen rotations).
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+Link: https://lore.kernel.org/r/20220813092753.6635-2-luke@ljones.dev
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/platform/x86/asus-nb-wmi.c | 15 +++++++++
+ drivers/platform/x86/asus-wmi.c | 37 ++++++++++++++++++++++
+ drivers/platform/x86/asus-wmi.h | 1 +
+ include/linux/platform_data/x86/asus-wmi.h | 1 +
+ 4 files changed, 54 insertions(+)
+
+diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
+index 4672a2b8322e..d9e7cf6e4a0e 100644
+--- a/drivers/platform/x86/asus-nb-wmi.c
++++ b/drivers/platform/x86/asus-nb-wmi.c
+@@ -123,6 +123,11 @@ static struct quirk_entry quirk_asus_use_lid_flip_devid = {
+ .tablet_switch_mode = asus_wmi_lid_flip_devid,
+ };
+
++static struct quirk_entry quirk_asus_tablet_mode = {
++ .wmi_backlight_set_devstate = true,
++ .tablet_switch_mode = asus_wmi_lid_flip_rog_devid,
++};
++
+ static int dmi_matched(const struct dmi_system_id *dmi)
+ {
+ pr_info("Identified laptop model '%s'\n", dmi->ident);
+@@ -471,6 +476,15 @@ static const struct dmi_system_id asus_quirks[] = {
+ },
+ .driver_data = &quirk_asus_use_lid_flip_devid,
+ },
++ {
++ .callback = dmi_matched,
++ .ident = "ASUS ROG FLOW X13",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "GV301Q"),
++ },
++ .driver_data = &quirk_asus_tablet_mode,
++ },
+ {},
+ };
+
+@@ -578,6 +592,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
+ { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
+ { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */
+ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */
++ { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */
+ { KE_END, 0},
+ };
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index fe2d072e1acc..5352055848d0 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -68,6 +68,7 @@ module_param(fnlock_default, bool, 0444);
+ #define NOTIFY_KBD_FBM 0x99
+ #define NOTIFY_KBD_TTP 0xae
+ #define NOTIFY_LID_FLIP 0xfa
++#define NOTIFY_LID_FLIP_ROG 0xbd
+
+ #define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
+
+@@ -530,6 +531,19 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
+ dev_err(dev, "Error checking for lid-flip: %d\n", result);
+ }
+ break;
++ case asus_wmi_lid_flip_rog_devid:
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG);
++ if (result < 0)
++ asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
++ if (result >= 0) {
++ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
++ input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
++ } else if (result == -ENODEV) {
++ dev_err(dev, "This device has lid-flip-rog quirk but got ENODEV checking it. This is a bug.");
++ } else {
++ dev_err(dev, "Error checking for lid-flip: %d\n", result);
++ }
++ break;
+ }
+
+ err = input_register_device(asus->inputdev);
+@@ -564,6 +578,17 @@ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
+ }
+ }
+
++static void lid_flip_rog_tablet_mode_get_state(struct asus_wmi *asus)
++{
++ int result;
++
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG);
++ if (result >= 0) {
++ input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
++ input_sync(asus->inputdev);
++ }
++}
++
+ /* dGPU ********************************************************************/
+ static ssize_t dgpu_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+@@ -3069,6 +3094,12 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+ return;
+ }
+
++ if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_rog_devid &&
++ code == NOTIFY_LID_FLIP_ROG) {
++ lid_flip_rog_tablet_mode_get_state(asus);
++ return;
++ }
++
+ if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
+ fan_boost_mode_switch_next(asus);
+ return;
+@@ -3701,6 +3732,9 @@ static int asus_hotk_resume(struct device *device)
+ case asus_wmi_lid_flip_devid:
+ lid_flip_tablet_mode_get_state(asus);
+ break;
++ case asus_wmi_lid_flip_rog_devid:
++ lid_flip_rog_tablet_mode_get_state(asus);
++ break;
+ }
+
+ return 0;
+@@ -3749,6 +3783,9 @@ static int asus_hotk_restore(struct device *device)
+ case asus_wmi_lid_flip_devid:
+ lid_flip_tablet_mode_get_state(asus);
+ break;
++ case asus_wmi_lid_flip_rog_devid:
++ lid_flip_rog_tablet_mode_get_state(asus);
++ break;
+ }
+
+ return 0;
+diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
+index 413920bad0c6..0187f13d2414 100644
+--- a/drivers/platform/x86/asus-wmi.h
++++ b/drivers/platform/x86/asus-wmi.h
+@@ -29,6 +29,7 @@ enum asus_wmi_tablet_switch_mode {
+ asus_wmi_no_tablet_switch,
+ asus_wmi_kbd_dock_devid,
+ asus_wmi_lid_flip_devid,
++ asus_wmi_lid_flip_rog_devid,
+ };
+
+ struct quirk_entry {
+diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
+index 70d2347bf6ca..6e8a95c10d17 100644
+--- a/include/linux/platform_data/x86/asus-wmi.h
++++ b/include/linux/platform_data/x86/asus-wmi.h
+@@ -65,6 +65,7 @@
+ #define ASUS_WMI_DEVID_PANEL_OD 0x00050019
+ #define ASUS_WMI_DEVID_CAMERA 0x00060013
+ #define ASUS_WMI_DEVID_LID_FLIP 0x00060062
++#define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077
+
+ /* Storage */
+ #define ASUS_WMI_DEVID_CARDREADER 0x00080013
+--
+2.37.2
+
+From c98dc61ee08f833e68337700546e120e2edac7c9 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 24 Aug 2022 17:11:44 +0200
+Subject: [PATCH 13/19] platform/x86: asus-wmi: Simplify tablet-mode-switch
+ probing
+
+The 3 different tablet-mode-switch initialization paths repeat a lot
+of the same code. Add a helper function for this.
+
+This also makes the error-handling for the kbd_dock_devid case consistent
+with the other 2 cases.
+
+Cc: Luke D. Jones <luke@ljones.dev>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20220824151145.1448010-1-hdegoede@redhat.com
+---
+ drivers/platform/x86/asus-wmi.c | 55 +++++++++++++--------------------
+ 1 file changed, 22 insertions(+), 33 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 5352055848d0..d71daa024752 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -484,13 +484,28 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
+ }
+
+ /* Input **********************************************************************/
++static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code)
++{
++ struct device *dev = &asus->platform_device->dev;
++ int result;
++
++ result = asus_wmi_get_devstate_simple(asus, dev_id);
++ if (result < 0)
++ asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
++ if (result >= 0) {
++ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
++ input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
++ } else if (result == -ENODEV) {
++ dev_err(dev, "This device has tablet-mode-switch quirk but got ENODEV checking it. This is a bug.");
++ } else {
++ dev_err(dev, "Error checking for tablet-mode-switch: %d\n", result);
++ }
++}
+
+ static int asus_wmi_input_init(struct asus_wmi *asus)
+ {
+- struct device *dev;
+- int err, result;
+-
+- dev = &asus->platform_device->dev;
++ struct device *dev = &asus->platform_device->dev;
++ int err;
+
+ asus->inputdev = input_allocate_device();
+ if (!asus->inputdev)
+@@ -510,39 +525,13 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
+ case asus_wmi_no_tablet_switch:
+ break;
+ case asus_wmi_kbd_dock_devid:
+- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
+- if (result >= 0) {
+- input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+- input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
+- } else if (result != -ENODEV) {
+- dev_err(dev, "Error checking for keyboard-dock: %d\n", result);
+- }
++ asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE);
+ break;
+ case asus_wmi_lid_flip_devid:
+- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
+- if (result < 0)
+- asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
+- if (result >= 0) {
+- input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+- input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+- } else if (result == -ENODEV) {
+- dev_err(dev, "This device has lid_flip quirk but got ENODEV checking it. This is a bug.");
+- } else {
+- dev_err(dev, "Error checking for lid-flip: %d\n", result);
+- }
++ asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP, NOTIFY_LID_FLIP);
+ break;
+ case asus_wmi_lid_flip_rog_devid:
+- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG);
+- if (result < 0)
+- asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
+- if (result >= 0) {
+- input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+- input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+- } else if (result == -ENODEV) {
+- dev_err(dev, "This device has lid-flip-rog quirk but got ENODEV checking it. This is a bug.");
+- } else {
+- dev_err(dev, "Error checking for lid-flip: %d\n", result);
+- }
++ asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP_ROG, NOTIFY_LID_FLIP_ROG);
+ break;
+ }
+
+--
+2.37.2
+
+From 1ea0d3b46798afc35c3185f6058b8bc08525d56c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 24 Aug 2022 17:11:45 +0200
+Subject: [PATCH 14/19] platform/x86: asus-wmi: Simplify tablet-mode-switch
+ handling
+
+Simplify tablet-mode-switch handling:
+1. The code is the same for all variants, the only difference is the
+ dev_id and notify event code. Store the dev_id + code in struct asus_wmi
+ and unify the handling
+2. Make the new unified asus_wmi_tablet_mode_get_state() check dev_id has
+ been set and make it a no-op when not set. This allows calling it
+ unconditionally at resume/restore time
+3. Simplify the tablet_mode_sw module-param handling, this also allows
+ selecting the new lid-flip-rog type through the module-param.
+
+Cc: Luke D. Jones <luke@ljones.dev>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://lore.kernel.org/r/20220824151145.1448010-2-hdegoede@redhat.com
+---
+ drivers/platform/x86/asus-nb-wmi.c | 13 +----
+ drivers/platform/x86/asus-wmi.c | 76 ++++++------------------------
+ 2 files changed, 16 insertions(+), 73 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
+index d9e7cf6e4a0e..cb8af61d684c 100644
+--- a/drivers/platform/x86/asus-nb-wmi.c
++++ b/drivers/platform/x86/asus-nb-wmi.c
+@@ -504,17 +504,8 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
+ else
+ wapf = quirks->wapf;
+
+- switch (tablet_mode_sw) {
+- case 0:
+- quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
+- break;
+- case 1:
+- quirks->tablet_switch_mode = asus_wmi_kbd_dock_devid;
+- break;
+- case 2:
+- quirks->tablet_switch_mode = asus_wmi_lid_flip_devid;
+- break;
+- }
++ if (tablet_mode_sw != -1)
++ quirks->tablet_switch_mode = tablet_mode_sw;
+
+ if (quirks->i8042_filter) {
+ ret = i8042_install_filter(quirks->i8042_filter);
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index d71daa024752..0f9f79f249c7 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -222,6 +222,9 @@ struct asus_wmi {
+ struct asus_rfkill gps;
+ struct asus_rfkill uwb;
+
++ int tablet_switch_event_code;
++ u32 tablet_switch_dev_id;
++
+ enum fan_type fan_type;
+ int fan_pwm_mode;
+ int agfn_pwm;
+@@ -490,11 +493,11 @@ static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event
+ int result;
+
+ result = asus_wmi_get_devstate_simple(asus, dev_id);
+- if (result < 0)
+- asus->driver->quirks->tablet_switch_mode = asus_wmi_no_tablet_switch;
+ if (result >= 0) {
+ input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+ input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
++ asus->tablet_switch_dev_id = dev_id;
++ asus->tablet_switch_event_code = event_code;
+ } else if (result == -ENODEV) {
+ dev_err(dev, "This device has tablet-mode-switch quirk but got ENODEV checking it. This is a bug.");
+ } else {
+@@ -556,22 +559,14 @@ static void asus_wmi_input_exit(struct asus_wmi *asus)
+
+ /* Tablet mode ****************************************************************/
+
+-static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
++static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
+ {
+ int result;
+
+- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
+- if (result >= 0) {
+- input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+- input_sync(asus->inputdev);
+- }
+-}
+-
+-static void lid_flip_rog_tablet_mode_get_state(struct asus_wmi *asus)
+-{
+- int result;
++ if (!asus->tablet_switch_dev_id)
++ return;
+
+- result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP_ROG);
++ result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id);
+ if (result >= 0) {
+ input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+ input_sync(asus->inputdev);
+@@ -3020,9 +3015,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+ {
+ unsigned int key_value = 1;
+ bool autorelease = 1;
+- int result, orig_code;
+-
+- orig_code = code;
++ int orig_code = code;
+
+ if (asus->driver->key_filter) {
+ asus->driver->key_filter(asus->driver, &code, &key_value,
+@@ -3065,27 +3058,8 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+ return;
+ }
+
+- if (asus->driver->quirks->tablet_switch_mode == asus_wmi_kbd_dock_devid &&
+- code == NOTIFY_KBD_DOCK_CHANGE) {
+- result = asus_wmi_get_devstate_simple(asus,
+- ASUS_WMI_DEVID_KBD_DOCK);
+- if (result >= 0) {
+- input_report_switch(asus->inputdev, SW_TABLET_MODE,
+- !result);
+- input_sync(asus->inputdev);
+- }
+- return;
+- }
+-
+- if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_devid &&
+- code == NOTIFY_LID_FLIP) {
+- lid_flip_tablet_mode_get_state(asus);
+- return;
+- }
+-
+- if (asus->driver->quirks->tablet_switch_mode == asus_wmi_lid_flip_rog_devid &&
+- code == NOTIFY_LID_FLIP_ROG) {
+- lid_flip_rog_tablet_mode_get_state(asus);
++ if (code == asus->tablet_switch_event_code) {
++ asus_wmi_tablet_mode_get_state(asus);
+ return;
+ }
+
+@@ -3714,18 +3688,7 @@ static int asus_hotk_resume(struct device *device)
+ if (asus_wmi_has_fnlock_key(asus))
+ asus_wmi_fnlock_update(asus);
+
+- switch (asus->driver->quirks->tablet_switch_mode) {
+- case asus_wmi_no_tablet_switch:
+- case asus_wmi_kbd_dock_devid:
+- break;
+- case asus_wmi_lid_flip_devid:
+- lid_flip_tablet_mode_get_state(asus);
+- break;
+- case asus_wmi_lid_flip_rog_devid:
+- lid_flip_rog_tablet_mode_get_state(asus);
+- break;
+- }
+-
++ asus_wmi_tablet_mode_get_state(asus);
+ return 0;
+ }
+
+@@ -3765,18 +3728,7 @@ static int asus_hotk_restore(struct device *device)
+ if (asus_wmi_has_fnlock_key(asus))
+ asus_wmi_fnlock_update(asus);
+
+- switch (asus->driver->quirks->tablet_switch_mode) {
+- case asus_wmi_no_tablet_switch:
+- case asus_wmi_kbd_dock_devid:
+- break;
+- case asus_wmi_lid_flip_devid:
+- lid_flip_tablet_mode_get_state(asus);
+- break;
+- case asus_wmi_lid_flip_rog_devid:
+- lid_flip_rog_tablet_mode_get_state(asus);
+- break;
+- }
+-
++ asus_wmi_tablet_mode_get_state(asus);
+ return 0;
+ }
+
+--
+2.37.2
+
+From 79dd1bb11d84054aca1587f366e7c5d72da1e906 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Thu, 4 Aug 2022 14:14:45 +1200
+Subject: [PATCH 15/19] sound: realtek: Add pincfg for ASUS G533Z
+
+Fixes up the pincfg for ASUS ROG Strix G15 (G533Z) laptop.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ sound/pci/hda/patch_realtek.c | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index fd630d62b5a0..e9cad49ee2a5 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -5828,7 +5828,7 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
+ struct alc_spec *spec = codec->spec;
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+ alc255_set_default_jack_type(codec);
+- }
++ }
+ else
+ alc_fixup_headset_mode(codec, fix, action);
+ }
+@@ -7022,6 +7022,7 @@ enum {
+ ALC294_FIXUP_ASUS_GX502_HP,
+ ALC294_FIXUP_ASUS_GX502_PINS,
+ ALC294_FIXUP_ASUS_GX502_VERBS,
++ ALC285_FIXUP_ASUS_G533Z_PINS,
+ ALC294_FIXUP_ASUS_GU502_HP,
+ ALC294_FIXUP_ASUS_GU502_PINS,
+ ALC294_FIXUP_ASUS_GU502_VERBS,
+@@ -8363,6 +8364,17 @@ static const struct hda_fixup alc269_fixups[] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc294_fixup_gu502_hp,
+ },
++ [ALC285_FIXUP_ASUS_G533Z_PINS] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x14, 0x90170120 },
++ { 0x19, 0x03A11050 }, /* front HP mic */
++ { 0x1B, 0x03A11C30 }, /* rear external mic */
++ { 0x21, 0x03211420 }, /* front HP out */
++ { }
++ },
++ .chained = false,
++ },
+ [ALC294_FIXUP_ASUS_COEF_1B] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+@@ -9294,6 +9306,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
+ SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
+ SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
++ SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
+ SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
+--
+2.37.2
+
+From 522525c97357f768c0fba8705535766ce2ea467f Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 12 Aug 2022 13:24:07 +1200
+Subject: [PATCH 16/19] sound: realtek: Add pincfg for ASUS G513
+
+Fixes up the pincfg for ASUS ROG Strix G513
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ sound/pci/hda/patch_realtek.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index e9cad49ee2a5..abf3fb50692a 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -7023,6 +7023,7 @@ enum {
+ ALC294_FIXUP_ASUS_GX502_PINS,
+ ALC294_FIXUP_ASUS_GX502_VERBS,
+ ALC285_FIXUP_ASUS_G533Z_PINS,
++ ALC294_FIXUP_ASUS_G513_PINS,
+ ALC294_FIXUP_ASUS_GU502_HP,
+ ALC294_FIXUP_ASUS_GU502_PINS,
+ ALC294_FIXUP_ASUS_GU502_VERBS,
+@@ -8308,6 +8309,16 @@ static const struct hda_fixup alc269_fixups[] = {
+ .chained = true,
+ .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+ },
++ [ALC294_FIXUP_ASUS_G513_PINS] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x19, 0x03a11050 }, /* front HP mic */
++ { 0x1a, 0x03a11c30 }, /* rear external mic */
++ { 0x21, 0x03211420 }, /* front HP out */
++ { }
++ },
++ .chained = false
++ },
+ [ALC294_FIXUP_ASUS_GX502_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+@@ -9307,6 +9318,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
+ SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
+ SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
++ SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS),
+ SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
+--
+2.37.2
+
+From 4e821f67963ae0c4dcceadb561077164da5ac79a Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 26 Aug 2022 10:32:34 +1200
+Subject: [PATCH 17/19] asus-wmi: Implement TUF laptop keyboard LED modes
+
+Adds support for changing the laptop keyboard LED mode and colour.
+
+The modes are visible effects such as static, rainbow, pulsing,
+colour cycles.
+
+These sysfs attributes are added to asus::kbd_backlight:
+- kbd_rgb_mode
+- kbd_rgb_mode_index
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-wmi.c | 76 +++++++++++++++++++++-
+ include/linux/platform_data/x86/asus-wmi.h | 3 +
+ 2 files changed, 78 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 0f9f79f249c7..92f16bb9b4ef 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -237,6 +237,8 @@ struct asus_wmi {
+ bool dgpu_disable_available;
+ bool gpu_mux_mode_available;
+
++ bool kbd_rgb_mode_available;
++
+ bool throttle_thermal_policy_available;
+ u8 throttle_thermal_policy_mode;
+
+@@ -720,6 +722,69 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
+ }
+ static DEVICE_ATTR_RW(gpu_mux_mode);
+
++/* TUF Laptop Keyboard RGB Modes **********************************************/
++static ssize_t kbd_rgb_mode_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ u32 cmd, mode, r, g, b, speed;
++ int err;
++
++ if (sscanf(buf, "%d %d %d %d %d %d", &cmd, &mode, &r, &g, &b, &speed) != 6)
++ return -EINVAL;
++
++ cmd = !!cmd;
++
++ /* These are the known usable modes across all TUF/ROG */
++ if (mode >= 12 || mode == 9)
++ mode = 10;
++
++ switch (speed) {
++ case 0:
++ speed = 0xe1;
++ break;
++ case 1:
++ speed = 0xeb;
++ break;
++ case 2:
++ speed = 0xf5;
++ break;
++ default:
++ speed = 0xeb;
++ }
++
++ err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, ASUS_WMI_DEVID_TUF_RGB_MODE,
++ cmd | (mode << 8) | (r << 16) | (g << 24), b | (speed << 8), NULL);
++ if (err)
++ return err;
++
++ return count;
++}
++static DEVICE_ATTR_WO(kbd_rgb_mode);
++
++static ssize_t kbd_rgb_mode_index_show(struct device *device,
++ struct device_attribute *attr,
++ char *buf)
++{
++ return sysfs_emit(buf, "%s\n", "cmd mode red green blue speed");
++}
++static DEVICE_ATTR_RO(kbd_rgb_mode_index);
++
++static struct attribute *kbd_rgb_mode_attrs[] = {
++ &dev_attr_kbd_rgb_mode.attr,
++ &dev_attr_kbd_rgb_mode_index.attr,
++ NULL,
++};
++
++static const struct attribute_group kbd_rgb_mode_group = {
++ .attrs = kbd_rgb_mode_attrs,
++};
++
++const struct attribute_group *kbd_rgb_mode_groups[] = {
++ NULL,
++ NULL,
++};
++
+ /* Battery ********************************************************************/
+
+ /* The battery maximum charging percentage */
+@@ -1038,7 +1103,10 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
+
+ static int asus_wmi_led_init(struct asus_wmi *asus)
+ {
+- int rv = 0, led_val;
++ int rv = 0, num_rgb_groups = 0, led_val;
++
++ if (asus->kbd_rgb_mode_available)
++ kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group;
+
+ asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!asus->led_workqueue)
+@@ -1066,6 +1134,9 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
+ asus->kbd_led.brightness_get = kbd_led_get;
+ asus->kbd_led.max_brightness = 3;
+
++ if (num_rgb_groups != 0)
++ asus->kbd_led.groups = kbd_rgb_mode_groups;
++
+ rv = led_classdev_register(&asus->platform_device->dev,
+ &asus->kbd_led);
+ if (rv)
+@@ -3253,6 +3324,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
+ ok = asus->egpu_enable_available;
+ else if (attr == &dev_attr_dgpu_disable.attr)
+ ok = asus->dgpu_disable_available;
++ else if (attr == &dev_attr_dgpu_disable.attr)
++ ok = asus->dgpu_disable_available;
+ else if (attr == &dev_attr_gpu_mux_mode.attr)
+ ok = asus->gpu_mux_mode_available;
+ else if (attr == &dev_attr_fan_boost_mode.attr)
+@@ -3519,6 +3592,7 @@ static int asus_wmi_add(struct platform_device *pdev)
+ asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
+ asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
+ asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
++ asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
+ asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
+
+ err = fan_boost_mode_check_present(asus);
+diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
+index 6e8a95c10d17..3d861477cb20 100644
+--- a/include/linux/platform_data/x86/asus-wmi.h
++++ b/include/linux/platform_data/x86/asus-wmi.h
+@@ -103,6 +103,9 @@
+ /* gpu mux switch, 0 = dGPU, 1 = Optimus */
+ #define ASUS_WMI_DEVID_GPU_MUX 0x00090016
+
++/* TUF laptop RGB modes/colours */
++#define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056
++
+ /* DSTS masks */
+ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
+ #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
+--
+2.37.2
+
+From fa211b90a6ed8973cb50b478a7cb250f5d8d0a12 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 26 Aug 2022 10:33:20 +1200
+Subject: [PATCH 18/19] asus-wmi: Implement TUF laptop keyboard power states
+
+Adds support for setting various power states of TUF keyboards.
+These states are combinations of:
+- boot, set if a boot animation is shown on keyboard
+- awake, set if the keyboard LEDs are visible while laptop is on
+- sleep, set if an animation is displayed while the laptop is suspended
+- keyboard (unknown effect)
+
+Adds two sysfs attributes to asus::kbd_backlight:
+- kbd_rgb_state
+- kbd_rgb_state_index
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-wmi.c | 57 ++++++++++++++++++++++
+ include/linux/platform_data/x86/asus-wmi.h | 3 ++
+ 2 files changed, 60 insertions(+)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 92f16bb9b4ef..f608a4467d99 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -238,6 +238,7 @@ struct asus_wmi {
+ bool gpu_mux_mode_available;
+
+ bool kbd_rgb_mode_available;
++ bool kbd_rgb_state_available;
+
+ bool throttle_thermal_policy_available;
+ u8 throttle_thermal_policy_mode;
+@@ -780,9 +781,62 @@ static const struct attribute_group kbd_rgb_mode_group = {
+ .attrs = kbd_rgb_mode_attrs,
+ };
+
++/* TUF Laptop Keyboard RGB State **********************************************/
++static ssize_t kbd_rgb_state_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ u32 flags, cmd, boot, awake, sleep, keyboard;
++ int err;
++
++ if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &keyboard) != 5)
++ return -EINVAL;
++
++ if (cmd)
++ cmd = BIT(2);
++
++ flags = 0;
++ if (boot)
++ flags |= BIT(1);
++ if (awake)
++ flags |= BIT(3);
++ if (sleep)
++ flags |= BIT(5);
++ if (keyboard)
++ flags |= BIT(7);
++
++ /* 0xbd is the required default arg0 for the method. Nothing happens otherwise */
++ err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS,
++ ASUS_WMI_DEVID_TUF_RGB_STATE, 0xbd | cmd << 8 | (flags << 16), 0, NULL);
++ if (err)
++ return err;
++
++ return count;
++}
++static DEVICE_ATTR_WO(kbd_rgb_state);
++
++static ssize_t kbd_rgb_state_index_show(struct device *device,
++ struct device_attribute *attr,
++ char *buf)
++{
++ return sysfs_emit(buf, "%s\n", "cmd boot awake sleep keyboard");
++}
++static DEVICE_ATTR_RO(kbd_rgb_state_index);
++
++static struct attribute *kbd_rgb_state_attrs[] = {
++ &dev_attr_kbd_rgb_state.attr,
++ &dev_attr_kbd_rgb_state_index.attr,
++ NULL,
++};
++
++static const struct attribute_group kbd_rgb_state_group = {
++ .attrs = kbd_rgb_state_attrs,
++};
++
+ const struct attribute_group *kbd_rgb_mode_groups[] = {
+ NULL,
+ NULL,
++ NULL,
+ };
+
+ /* Battery ********************************************************************/
+@@ -1107,6 +1161,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
+
+ if (asus->kbd_rgb_mode_available)
+ kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group;
++ if (asus->kbd_rgb_state_available)
++ kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_state_group;
+
+ asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!asus->led_workqueue)
+@@ -3593,6 +3649,7 @@ static int asus_wmi_add(struct platform_device *pdev)
+ asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
+ asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
+ asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
++ asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
+ asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
+
+ err = fan_boost_mode_check_present(asus);
+diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
+index 3d861477cb20..7dd580fdc61c 100644
+--- a/include/linux/platform_data/x86/asus-wmi.h
++++ b/include/linux/platform_data/x86/asus-wmi.h
+@@ -106,6 +106,9 @@
+ /* TUF laptop RGB modes/colours */
+ #define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056
+
++/* TUF laptop RGB power/state */
++#define ASUS_WMI_DEVID_TUF_RGB_STATE 0x00100057
++
+ /* DSTS masks */
+ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
+ #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
+--
+2.37.2
+
+From 3f73788b14ada783657e5e6303c4e5de5e096be5 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 26 Aug 2022 12:32:24 +1200
+Subject: [PATCH 20/21] asus-wmi: Modify behaviour of Fn+F5 fan key
+
+Some more recent TUF laptops have both fan_boost and thermal_throttle.
+The key code for Fn+F5 is also different and unmapped.
+
+This patch adjusts the asus_wmi_handle_event_code() match to match
+for both 0x99 and 0xAE, and run both mode switch functions for
+fan_boost and/or thermal_throttle if either are available.
+
+It is required that both are tried, as in some instances the ACPI
+set-method for one may not have any code body within it even though
+it was returned as supported by the get method.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-nb-wmi.c | 1 +
+ drivers/platform/x86/asus-wmi.c | 11 +++++------
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
+index cb8af61d684c..fcfe6dddd645 100644
+--- a/drivers/platform/x86/asus-nb-wmi.c
++++ b/drivers/platform/x86/asus-nb-wmi.c
+@@ -577,6 +577,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
+ { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
+ { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
+ { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
++ { KE_KEY, 0xAE, { KEY_FN_F5 } }, /* Fn+F5 fan mode on 2020+ */
+ { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */
+ { KE_KEY, 0xB5, { KEY_CALC } },
+ { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index f608a4467d99..ea45e10302f7 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -3190,14 +3190,13 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
+ return;
+ }
+
+- if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
+- fan_boost_mode_switch_next(asus);
++ if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) {
++ if (asus->fan_boost_mode_available)
++ fan_boost_mode_switch_next(asus);
++ if (asus->throttle_thermal_policy_available)
++ throttle_thermal_policy_switch_next(asus);
+ return;
+- }
+
+- if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) {
+- throttle_thermal_policy_switch_next(asus);
+- return;
+ }
+
+ if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
+--
+2.37.2
+
+From fe443cc4ff4e12652af1cdae63cff354a2467b67 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 26 Aug 2022 12:34:02 +1200
+Subject: [PATCH 21/21] asus-wmi: Support the GPU fan on TUF laptops
+
+Add support for TUF laptops which have the ability to control
+the GPU fan. This will show as a second fan in hwmon, and has
+the ability to run as boost (fullspeed), or auto.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-wmi.c | 71 ++++++++++++++++++++++
+ include/linux/platform_data/x86/asus-wmi.h | 1 +
+ 2 files changed, 72 insertions(+)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index ea45e10302f7..d05684194f2d 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -226,7 +226,9 @@ struct asus_wmi {
+ u32 tablet_switch_dev_id;
+
+ enum fan_type fan_type;
++ enum fan_type gpu_fan_type;
+ int fan_pwm_mode;
++ int gpu_fan_pwm_mode;
+ int agfn_pwm;
+
+ bool fan_boost_mode_available;
+@@ -1861,6 +1863,18 @@ static int asus_fan_set_auto(struct asus_wmi *asus)
+ return -ENXIO;
+ }
+
++ /*
++ * Modern models like the G713 also have GPU fan control (this is not AGFN)
++ */
++ if (asus->gpu_fan_type == FAN_TYPE_SPEC83) {
++ status = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL,
++ 0, &retval);
++ if (status)
++ return status;
++
++ if (retval != 1)
++ return -EIO;
++ }
+
+ return 0;
+ }
+@@ -2063,9 +2077,57 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
+ deci_kelvin_to_millicelsius(value & 0xFFFF));
+ }
+
++/* GPU fan on modern ROG laptops */
++static ssize_t pwm2_enable_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct asus_wmi *asus = dev_get_drvdata(dev);
++
++ return sysfs_emit(buf, "%d\n", asus->gpu_fan_pwm_mode);
++}
++
++static ssize_t pwm2_enable_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct asus_wmi *asus = dev_get_drvdata(dev);
++ int state;
++ int value;
++ int ret;
++ u32 retval;
++
++ ret = kstrtouint(buf, 10, &state);
++ if (ret)
++ return ret;
++
++ switch (state) { /* standard documented hwmon values */
++ case ASUS_FAN_CTRL_FULLSPEED:
++ value = 1;
++ break;
++ case ASUS_FAN_CTRL_AUTO:
++ value = 0;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL,
++ value, &retval);
++ if (ret)
++ return ret;
++
++ if (retval != 1)
++ return -EIO;
++
++ asus->gpu_fan_pwm_mode = state;
++ return count;
++}
++
+ /* Fan1 */
+ static DEVICE_ATTR_RW(pwm1);
+ static DEVICE_ATTR_RW(pwm1_enable);
++static DEVICE_ATTR_RW(pwm2_enable);
+ static DEVICE_ATTR_RO(fan1_input);
+ static DEVICE_ATTR_RO(fan1_label);
+
+@@ -2075,6 +2137,7 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
+ static struct attribute *hwmon_attributes[] = {
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
++ &dev_attr_pwm2_enable.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_label.attr,
+
+@@ -2097,6 +2160,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
+ || attr == &dev_attr_pwm1_enable.attr) {
+ if (asus->fan_type == FAN_TYPE_NONE)
+ return 0;
++ } else if (attr == &dev_attr_pwm2_enable.attr) {
++ if (asus->gpu_fan_type == FAN_TYPE_NONE)
++ return 0;
+ } else if (attr == &dev_attr_temp1_input.attr) {
+ int err = asus_wmi_get_devstate(asus,
+ ASUS_WMI_DEVID_THERMAL_CTRL,
+@@ -2139,6 +2205,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
+
+ static int asus_wmi_fan_init(struct asus_wmi *asus)
+ {
++ asus->gpu_fan_type = FAN_TYPE_NONE;
+ asus->fan_type = FAN_TYPE_NONE;
+ asus->agfn_pwm = -1;
+
+@@ -2147,6 +2214,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
+ else if (asus_wmi_has_agfn_fan(asus))
+ asus->fan_type = FAN_TYPE_AGFN;
+
++ /* Modern models like G713 also have GPU fan control */
++ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL))
++ asus->gpu_fan_type = FAN_TYPE_SPEC83;
++
+ if (asus->fan_type == FAN_TYPE_NONE)
+ return -ENODEV;
+
+diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
+index 7dd580fdc61c..28234dc9fa6a 100644
+--- a/include/linux/platform_data/x86/asus-wmi.h
++++ b/include/linux/platform_data/x86/asus-wmi.h
+@@ -79,6 +79,7 @@
+ #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
+ #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */
+ #define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013
++#define ASUS_WMI_DEVID_GPU_FAN_CTRL 0x00110014
+ #define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024
+ #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
+
+--
+2.37.2
+
diff --git a/SOURCES/kernel-aarch64-debug-fedora.config b/SOURCES/kernel-aarch64-debug-fedora.config
index a520766..dbb93ff 100644
--- a/SOURCES/kernel-aarch64-debug-fedora.config
+++ b/SOURCES/kernel-aarch64-debug-fedora.config
@@ -369,6 +369,7 @@ CONFIG_ARM64_ERRATUM_2119858=y
CONFIG_ARM64_ERRATUM_2139208=y
CONFIG_ARM64_ERRATUM_2224489=y
CONFIG_ARM64_ERRATUM_2253138=y
+CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_ERRATUM_819472=y
CONFIG_ARM64_ERRATUM_824069=y
CONFIG_ARM64_ERRATUM_826319=y
diff --git a/SOURCES/kernel-aarch64-debug-rhel.config b/SOURCES/kernel-aarch64-debug-rhel.config
index 4128e93..3d51614 100644
--- a/SOURCES/kernel-aarch64-debug-rhel.config
+++ b/SOURCES/kernel-aarch64-debug-rhel.config
@@ -294,6 +294,7 @@ CONFIG_ARM64_ERRATUM_2119858=y
CONFIG_ARM64_ERRATUM_2139208=y
CONFIG_ARM64_ERRATUM_2224489=y
CONFIG_ARM64_ERRATUM_2253138=y
+CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_ERRATUM_819472=y
CONFIG_ARM64_ERRATUM_824069=y
CONFIG_ARM64_ERRATUM_826319=y
diff --git a/SOURCES/kernel-aarch64-fedora.config b/SOURCES/kernel-aarch64-fedora.config
index eaa9cb9..a4db1bc 100644
--- a/SOURCES/kernel-aarch64-fedora.config
+++ b/SOURCES/kernel-aarch64-fedora.config
@@ -369,6 +369,7 @@ CONFIG_ARM64_ERRATUM_2119858=y
CONFIG_ARM64_ERRATUM_2139208=y
CONFIG_ARM64_ERRATUM_2224489=y
CONFIG_ARM64_ERRATUM_2253138=y
+CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_ERRATUM_819472=y
CONFIG_ARM64_ERRATUM_824069=y
CONFIG_ARM64_ERRATUM_826319=y
diff --git a/SOURCES/kernel-aarch64-rhel.config b/SOURCES/kernel-aarch64-rhel.config
index 62c6b66..861fd10 100644
--- a/SOURCES/kernel-aarch64-rhel.config
+++ b/SOURCES/kernel-aarch64-rhel.config
@@ -294,6 +294,7 @@ CONFIG_ARM64_ERRATUM_2119858=y
CONFIG_ARM64_ERRATUM_2139208=y
CONFIG_ARM64_ERRATUM_2224489=y
CONFIG_ARM64_ERRATUM_2253138=y
+CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_ERRATUM_819472=y
CONFIG_ARM64_ERRATUM_824069=y
CONFIG_ARM64_ERRATUM_826319=y
diff --git a/SOURCES/patch-5.19-redhat.patch b/SOURCES/patch-5.19-redhat.patch
index f5d5aee..a666806 100644
--- a/SOURCES/patch-5.19-redhat.patch
+++ b/SOURCES/patch-5.19-redhat.patch
@@ -251,7 +251,7 @@ index 000000000000..733a26bd887a
+
+endmenu
diff --git a/Makefile b/Makefile
-index cb68101ea070..da893ccb2025 100644
+index 3d88923df694..4f4e240c3d2b 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,10 @@ $(if $(filter __%, $(MAKECMDGOALS)), \
@@ -370,10 +370,10 @@ index ce9826bce29b..948d18e59cf5 100644
CONFIG_DRM_ETNAVIV=m
CONFIG_DRM_MXSFB=m
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
-index a5d1b561ed53..cd93c9041679 100644
+index 001eaba5a6b4..cc20aaacd741 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
-@@ -1145,7 +1145,7 @@ endchoice
+@@ -1162,7 +1162,7 @@ endchoice
config ARM64_FORCE_52BIT
bool "Force 52-bit virtual addresses for userspace"
@@ -382,7 +382,7 @@ index a5d1b561ed53..cd93c9041679 100644
help
For systems with 52-bit userspace VAs enabled, the kernel will attempt
to maintain compatibility with older software by providing 48-bit VAs
-@@ -1384,6 +1384,7 @@ config XEN
+@@ -1401,6 +1401,7 @@ config XEN
config FORCE_MAX_ZONEORDER
int
default "14" if ARM64_64K_PAGES