From edbfb7abc2ff480fb7218e6a792602ac15f16e65 Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Sun, 11 Sep 2022 23:18:31 +0200 Subject: kernel 5.19.7 --- ...Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch | 34 + SOURCES/amdgpu-regression.patch | 1178 +++++++++ SOURCES/asus-linux.patch | 2509 ++++++++++++++++++++ SOURCES/kernel-aarch64-debug-fedora.config | 1 + SOURCES/kernel-aarch64-debug-rhel.config | 1 + SOURCES/kernel-aarch64-fedora.config | 1 + SOURCES/kernel-aarch64-rhel.config | 1 + SOURCES/patch-5.19-redhat.patch | 8 +- SPECS/kernel.spec | 23 +- 9 files changed, 3746 insertions(+), 10 deletions(-) create mode 100644 SOURCES/0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch create mode 100644 SOURCES/amdgpu-regression.patch create mode 100644 SOURCES/asus-linux.patch 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 +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 +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 + +v5: + - fix merge conflict issue + +v6: + - fix warnings reported by kernel test robot + +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 +Acked-by: Christian König +Link: https://patchwork.freedesktop.org/patch/msgid/20220407224843.2416-1-Arunpravin.PaneerSelvam@amd.com +Signed-off-by: Christian König +--- + 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 + #include + ++#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 + #include ++#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 ++ ++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?= +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 +Reviewed-by: Alex Deucher +Reviewed-by: Arunpravin Paneer Selvam +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?= +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 +Acked-by: Alex Deucher +Reviewed-by: Arunpravin Paneer Selvam +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 +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 +Reported-by: Mike Lothian +Tested-by: Mike Lothian +Link: https://patchwork.freedesktop.org/patch/msgid/20220714101214.7620-1-Arunpravin.PaneerSelvam@amd.com +Reviewed-by: Christian König +Signed-off-by: Christian König +--- + 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" +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 +--- + 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" +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 +--- + 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" +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 +Reviewed-by: Andy Shevchenko +Link: https://lore.kernel.org/r/20220809025054.1626339-6-luke@ljones.dev +Signed-off-by: Hans de Goede +--- + 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 +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 +Signed-off-by: ye xingchen +Link: https://lore.kernel.org/r/20220811013203.16010-1-ye.xingchen@zte.com.cn +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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" +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 +Link: https://lore.kernel.org/r/20220812222509.292692-2-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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//dgpu_disable ++Date: Aug 2022 ++KernelVersion: 5.17 ++Contact: "Luke Jones" ++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" +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 +Link: https://lore.kernel.org/r/20220812222509.292692-3-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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//egpu_enable ++Date: Aug 2022 ++KernelVersion: 5.17 ++Contact: "Luke Jones" ++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" +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 +Link: https://lore.kernel.org/r/20220812222509.292692-4-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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//panel_od ++Date: Aug 2022 ++KernelVersion: 5.17 ++Contact: "Luke Jones" ++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" +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 +Link: https://lore.kernel.org/r/20220812222509.292692-5-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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" +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 +Link: https://lore.kernel.org/r/20220812222509.292692-6-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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" +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 +Link: https://lore.kernel.org/r/20220812222509.292692-7-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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 +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 +Signed-off-by: Hans de Goede +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" +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 +Link: https://lore.kernel.org/r/20220813092624.6228-1-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + .../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//gpu_mux_mode ++Date: Aug 2022 ++KernelVersion: 6.1 ++Contact: "Luke Jones" ++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//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" +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 +Link: https://lore.kernel.org/r/20220813092753.6635-1-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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" +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 +Link: https://lore.kernel.org/r/20220813092753.6635-2-luke@ljones.dev +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +--- + 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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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" +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 +--- + 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" +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 +--- + 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" +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 +--- + 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" +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 +--- + 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" +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 +--- + 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" +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 +--- + 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 diff --git a/SPECS/kernel.spec b/SPECS/kernel.spec index 9ba6c84..ff9d009 100755 --- a/SPECS/kernel.spec +++ b/SPECS/kernel.spec @@ -122,17 +122,17 @@ Summary: The Linux kernel # the --with-release option overrides this setting.) %define debugbuildsenabled 1 %define buildid .fsync -%define specversion 5.19.6 +%define specversion 5.19.7 %define patchversion 5.19 %define pkgrelease 200 %define kversion 5 -%define tarfile_release 5.19.6 +%define tarfile_release 5.19.7 # This is needed to do merge window version magic %define patchlevel 19 # This allows pkg_release to have configurable %%{?dist} tag -%define specrelease 202%{?buildid}%{?dist} +%define specrelease 204%{?buildid}%{?dist} # This defines the kabi tarball version -%define kabiversion 5.19.6 +%define kabiversion 5.19.7 # # End of genspec.sh variables @@ -870,9 +870,13 @@ Patch207: acso.patch # device specific patches Patch300: linux-surface.patch Patch301: steam-deck.patch +Patch302: asus-linux.patch + # temporary patches Patch400: v6-ACPI-skip-IRQ-override-on-AMD-Zen-platforms.patch +Patch401: 0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch +Patch402: amdgpu-regression.patch %endif @@ -1458,9 +1462,12 @@ ApplyOptionalPatch acso.patch # device specific patches ApplyOptionalPatch linux-surface.patch ApplyOptionalPatch steam-deck.patch +ApplyOptionalPatch asus-linux.patch # temporary patches ApplyOptionalPatch v6-ACPI-skip-IRQ-override-on-AMD-Zen-platforms.patch +ApplyOptionalPatch 0001-Revert-PCI-Add-a-REBAR-size-quirk-for-Sapphire-RX-56.patch +ApplyOptionalPatch amdgpu-regression.patch %endif @@ -3168,8 +3175,12 @@ fi # # %changelog -* Sat Sep 03 2022 Jan Drögehoff - 5.19.6-202.fsync -- Linux v5.19.6 futex2 zen openrgb +* Sun Sep 11 2022 Jan Drögehoff - 5.19.7-204.fsync +- Linux v5.19.7 futex2 zen openrgb + +* Mon Sep 05 2022 Justin M. Forbes [5.19.7-0] +- New config item for 5.19.7 (Justin M. Forbes) +- Linux v5.19.7 * Wed Aug 31 2022 Justin M. Forbes [5.19.6-0] - Revert "block: freeze the queue earlier in del_gendisk" (Justin M. Forbes) -- cgit v1.2.3