mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
drm fixes for 7.3-rc4
core: - fix vblank pending event leak ttm: - swapout fixes dma-buf: - scattergather fixes - enable dma-buf debug on debug kernels dma-fence: - fix signaling bit checks sched: - fix virtual runtime race msm: - DT: - Corrected indentation - Core: - Marked fbdev as system memory - GPU: - Fixed autosuspend cleanup on teardown - a750: fix timestamps - Increase GMU fw init timeout - Misc fixes/cleanups - DPU: - Fixed clock rounding, unbreaking newest platforms - Cleared pending flush state - DP: - Skip PUSH_IDLE when link was never enabled - Fixed bandwidth checks - HDMI: - Fixed runtime PM cleanup on probe failure xe: - shrinker related fixes - xe_mmio_gem fault handler and destroy fixes - xe disable i2c irq on unbind i915: - Revert a commit touching registers that don't necessarily exist - Check for negative numbers before passing to BIT() amdgpu: - SMU 14.x fix - DC IRQ fix - Runtime PM fix for P2P - RAS fix - PCIe reporting fix - DCN 6 fix - Device removal fix - DC MALL fix amdkfd: - GC 12.x fixes - Boundary checks - Mapping clear fix nouveau: - suspend/resume fixes gud: - out of bounds access fix - ignore damage clips in full update vc4: - use-after-free fix -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmqttwkACgkQDHTzWXnE hr73Ww//S+8xgr8cpmJxoUrOrTnd4yeX/oj+HSRkEHQPdNayOf+pNnP4y+nChfXi ddQ3jTRyG5JwNmXRG0ouKf9koQk/V54R8v9CBtNQYsN2K58xW6riCIaEeOUbe3r1 1IQgYCEfS32b7/9D2lo1768LbJ0KWBr6qznKrfvC7vJ62wK3F0B9EzOmsKSzLxd3 gdUfyxEbtgegKOAamCbUyJyuzCErGkMAtkQ0HnmQGYmqqBBRS7Uvl1HN10JMoLSM MmR40g+dsp6ZzBDywNrdmIGDv749o1/k/zm5i6c2hJSibYBPR5sWtKICwu1ND44u ts2HjJJdyhm5PLiS09i9nVUnMkzV0N2czIDZvt9izp8+k8P4Bh/y1iagda1G0U65 h7dp9j8WXMCApxXNjplNgjMLSO7g4UJI1rAWjxGY4ecu62XHErrZ6tbjrOVOaa1T Xh8IN4EqPr+tRSKnW4AxwwwA1EfxNwoJSxglAvBvIaCjEhRWRlj7Sdo0Wrtg3WKy sORar40ySYHR+MeAbabewjRoMPq1Nyqh4D2PrOv48a4MK7a6Fl5ed6EHpyOSHYKF 7tMbLLLtDMIYX24wd/j8CkvhcTp09iphzXSqmUlIBn3t1gbrXspzCQtRU0UrsamJ QSbtL+qUoYSsobmpYOzuTVnO8W4oOnnIYaLz+TpVNDd7o7nzZf0= =EC37 -----END PGP SIGNATURE----- Merge tag 'drm-fixes-2026-09-19' of https://gitlab.freedesktop.org/drm/kernel Pull drm fixes from Dave Airlie: "Things have picked back up a bit this week, mostly amdgpu, xe and msm this time. There are a bunch of scattered changes across the rest of drivers and core stuff, nouveau, i915. core: - fix vblank pending event leak ttm: - swapout fixes dma-buf: - scattergather fixes - enable dma-buf debug on debug kernels dma-fence: - fix signaling bit checks sched: - fix virtual runtime race msm: - DT: - Corrected indentation - Core: - Marked fbdev as system memory - GPU: - Fixed autosuspend cleanup on teardown - a750: fix timestamps - Increase GMU fw init timeout - Misc fixes/cleanups - DPU: - Fixed clock rounding, unbreaking newest platforms - Cleared pending flush state - DP: - Skip PUSH_IDLE when link was never enabled - Fixed bandwidth checks - HDMI: - Fixed runtime PM cleanup on probe failure xe: - shrinker related fixes - xe_mmio_gem fault handler and destroy fixes - xe disable i2c irq on unbind i915: - Revert a commit touching registers that don't necessarily exist - Check for negative numbers before passing to BIT() amdgpu: - SMU 14.x fix - DC IRQ fix - Runtime PM fix for P2P - RAS fix - PCIe reporting fix - DCN 6 fix - Device removal fix - DC MALL fix amdkfd: - GC 12.x fixes - Boundary checks - Mapping clear fix nouveau: - suspend/resume fixes gud: - out of bounds access fix - ignore damage clips in full update vc4: - use-after-free fix versilicon: - plane format fix longsoon: - blend mode property fix" * tag 'drm-fixes-2026-09-19' of https://gitlab.freedesktop.org/drm/kernel: (59 commits) drm/amd/display: fix MALL hysteresis timer underflow at high refresh rates drm/amdgpu: fix rmmio iounmap skipped on device removal drm/amdgpu: Skip KFD mapping clear before initialization drm/amd/display: Fix NULL dereference in dcn50/dcn60 init_hw drm/amdkfd: Avoid integer underflow in EOP ring size calculation. drm/amdkfd: Avoid integer underflow with ffs in EOP ring size calc drm/amdgpu: Fix GPU PCIe link capability reporting drm/amdgpu: check ras and obj before dereference drm/amdgpu: hold a runtime PM reference for P2P dma-buf attachments drm/amdkfd: implement restore_mqd callbacks for GFX12/12.1 drm/amd/display: Atomize IRQ register read/modify/write ops drm/amd/pm: report energy accumulator for smu 14.0.3 drm/loongson: Create blend mode property for cursor plane drm/xe/i2c: Disable IRQ on unbind Revert "drm/i915/display: Clear SEL_FETCH_PLANE_CTL on plane disable" drm/verisilicon: remove ARGB formats from primary plane drm/verisilicon: add primary modifier for format tables drm/verisilicon: set blend mode for the cursor plane drm/sched: Fix virtual runtime race drm/i915/display: check configuration index before shifting ...
This commit is contained in:
commit
40288c9206
|
|
@ -150,7 +150,7 @@ examples:
|
|||
reg = <0>;
|
||||
|
||||
dpu_intf0_out: endpoint {
|
||||
remote-endpoint = <&mdss_dp0_in>;
|
||||
remote-endpoint = <&mdss_dp0_in>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -352,9 +352,9 @@ examples:
|
|||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
reg = <1>;
|
||||
|
||||
mdss_dp_out: endpoint { };
|
||||
mdss_dp_out: endpoint { };
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -248,9 +248,9 @@ examples:
|
|||
remote-endpoint = <&usb_dp_qmpphy_dp_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dp_opp_table: opp-table {
|
||||
dp_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp-162000000 {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ examples:
|
|||
port@1 {
|
||||
reg = <1>;
|
||||
dpu_intf1_out: endpoint {
|
||||
remote-endpoint = <&mdss_dsi0_in>;
|
||||
remote-endpoint = <&mdss_dsi0_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -90,18 +90,18 @@ examples:
|
|||
compatible = "operating-points-v2";
|
||||
|
||||
opp-19200000 {
|
||||
opp-hz = /bits/ 64 <19200000>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>;
|
||||
opp-hz = /bits/ 64 <19200000>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>;
|
||||
};
|
||||
|
||||
opp-25600000 {
|
||||
opp-hz = /bits/ 64 <25600000>;
|
||||
required-opps = <&rpmhpd_opp_svs>;
|
||||
opp-hz = /bits/ 64 <25600000>;
|
||||
required-opps = <&rpmhpd_opp_svs>;
|
||||
};
|
||||
|
||||
opp-307200000 {
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
required-opps = <&rpmhpd_opp_nom>;
|
||||
opp-hz = /bits/ 64 <307200000>;
|
||||
required-opps = <&rpmhpd_opp_nom>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ examples:
|
|||
phys = <&mdss_dsi0_phy>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
|
|
|
|||
|
|
@ -208,47 +208,47 @@ examples:
|
|||
#sound-dai-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
mdss_dp0_in: endpoint {
|
||||
remote-endpoint = <&mdss_intf0_out>;
|
||||
};
|
||||
};
|
||||
mdss_dp0_in: endpoint {
|
||||
remote-endpoint = <&mdss_intf0_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
mdss_dp0_out: endpoint {
|
||||
};
|
||||
};
|
||||
mdss_dp0_out: endpoint {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdss_dp0_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp-160000000 {
|
||||
opp-hz = /bits/ 64 <160000000>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>;
|
||||
};
|
||||
opp-160000000 {
|
||||
opp-hz = /bits/ 64 <160000000>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>;
|
||||
};
|
||||
|
||||
opp-270000000 {
|
||||
opp-hz = /bits/ 64 <270000000>;
|
||||
required-opps = <&rpmhpd_opp_svs>;
|
||||
};
|
||||
opp-270000000 {
|
||||
opp-hz = /bits/ 64 <270000000>;
|
||||
required-opps = <&rpmhpd_opp_svs>;
|
||||
};
|
||||
|
||||
opp-540000000 {
|
||||
opp-hz = /bits/ 64 <540000000>;
|
||||
required-opps = <&rpmhpd_opp_svs_l1>;
|
||||
};
|
||||
opp-540000000 {
|
||||
opp-hz = /bits/ 64 <540000000>;
|
||||
required-opps = <&rpmhpd_opp_svs_l1>;
|
||||
};
|
||||
|
||||
opp-810000000 {
|
||||
opp-hz = /bits/ 64 <810000000>;
|
||||
required-opps = <&rpmhpd_opp_nom>;
|
||||
};
|
||||
opp-810000000 {
|
||||
opp-hz = /bits/ 64 <810000000>;
|
||||
required-opps = <&rpmhpd_opp_nom>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ config UDMABUF
|
|||
config DMABUF_DEBUG
|
||||
bool "DMA-BUF debug checks"
|
||||
depends on DMA_SHARED_BUFFER
|
||||
default y if DEBUG
|
||||
default y if DEBUG_KERNEL
|
||||
help
|
||||
This option enables additional checks for DMA-BUF importers and
|
||||
exporters. Specifically it validates that importers do not peek at the
|
||||
|
|
|
|||
|
|
@ -5,16 +5,18 @@
|
|||
*/
|
||||
#include <linux/dma-buf-mapping.h>
|
||||
#include <linux/dma-resv.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/align.h>
|
||||
|
||||
#define MAX_SG_ENT_SZ ALIGN_DOWN(UINT_MAX, PAGE_SIZE)
|
||||
|
||||
static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length,
|
||||
dma_addr_t addr)
|
||||
{
|
||||
unsigned int len, nents;
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
nents = DIV_ROUND_UP(length, UINT_MAX);
|
||||
for (i = 0; i < nents; i++) {
|
||||
len = min_t(size_t, length, UINT_MAX);
|
||||
while (length) {
|
||||
len = min(length, MAX_SG_ENT_SZ);
|
||||
length -= len;
|
||||
/*
|
||||
* DMABUF abuses scatterlist to create a scatterlist
|
||||
|
|
@ -24,8 +26,10 @@ static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length,
|
|||
* does not require the CPU list for mapping or unmapping.
|
||||
*/
|
||||
sg_set_page(sgl, NULL, 0, 0);
|
||||
sg_dma_address(sgl) = addr + (dma_addr_t)i * UINT_MAX;
|
||||
sg_dma_address(sgl) = addr;
|
||||
sg_dma_len(sgl) = len;
|
||||
addr += len;
|
||||
/* Unconditionally advance. On last segment, this becomes NULL */
|
||||
sgl = sg_next(sgl);
|
||||
}
|
||||
|
||||
|
|
@ -40,15 +44,19 @@ static unsigned int calc_sg_nents(struct dma_iova_state *state,
|
|||
size_t i;
|
||||
|
||||
if (!state || !dma_use_iova(state)) {
|
||||
for (i = 0; i < nr_ranges; i++)
|
||||
nents += DIV_ROUND_UP(phys_vec[i].len, UINT_MAX);
|
||||
for (i = 0; i < nr_ranges; i++) {
|
||||
unsigned int added = DIV_ROUND_UP(phys_vec[i].len, MAX_SG_ENT_SZ);
|
||||
|
||||
if (check_add_overflow(nents, added, &nents))
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* In IOVA case, there is only one SG entry which spans
|
||||
* for whole IOVA address space, but we need to make sure
|
||||
* that it fits sg->length, maybe we need more.
|
||||
*/
|
||||
nents = DIV_ROUND_UP(size, UINT_MAX);
|
||||
nents = DIV_ROUND_UP(size, MAX_SG_ENT_SZ);
|
||||
}
|
||||
|
||||
return nents;
|
||||
|
|
@ -95,9 +103,10 @@ struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach,
|
|||
size_t nr_ranges, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
unsigned int nents, mapped_len = 0;
|
||||
struct dma_buf_dma *dma;
|
||||
struct scatterlist *sgl;
|
||||
size_t mapped_len = 0;
|
||||
unsigned int nents;
|
||||
dma_addr_t addr;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
|
@ -133,6 +142,8 @@ struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach,
|
|||
}
|
||||
|
||||
nents = calc_sg_nents(dma->state, phys_vec, nr_ranges, size);
|
||||
|
||||
/* sg_alloc_table will cleanly fail and return -EINVAL if nents == 0 */
|
||||
ret = sg_alloc_table(&dma->sgt, nents, GFP_KERNEL | __GFP_ZERO);
|
||||
if (ret)
|
||||
goto err_free_state;
|
||||
|
|
|
|||
|
|
@ -1170,7 +1170,12 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence)
|
|||
|
||||
/* RCU protection is required for safe access to returned string */
|
||||
ops = rcu_dereference(fence->ops);
|
||||
if (ops)
|
||||
|
||||
/*
|
||||
* Make load ordering irrelevant by checking both signaled state and ops
|
||||
* pointer and ops pointer is only set to NULL on newer implementations.
|
||||
*/
|
||||
if (!dma_fence_test_signaled_flag(fence) && ops)
|
||||
return (const char __rcu *)ops->get_driver_name(fence);
|
||||
else
|
||||
return (const char __rcu *)"detached-driver";
|
||||
|
|
@ -1203,7 +1208,12 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence)
|
|||
|
||||
/* RCU protection is required for safe access to returned string */
|
||||
ops = rcu_dereference(fence->ops);
|
||||
if (ops)
|
||||
|
||||
/*
|
||||
* Make load ordering irrelevant by checking both signaled state and ops
|
||||
* pointer and ops pointer is only set to NULL on newer implementations.
|
||||
*/
|
||||
if (!dma_fence_test_signaled_flag(fence) && ops)
|
||||
return (const char __rcu *)ops->get_timeline_name(fence);
|
||||
else
|
||||
return (const char __rcu *)"signaled-timeline";
|
||||
|
|
|
|||
|
|
@ -621,6 +621,9 @@ enum amdgpu_enforce_isolation_mode {
|
|||
struct amdgpu_device {
|
||||
struct device *dev;
|
||||
struct pci_dev *pdev;
|
||||
/* The two ends of the physical PCIe link outside the device. */
|
||||
struct pci_dev *link_dev;
|
||||
struct pci_dev *link_partner;
|
||||
struct drm_device ddev;
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_ACP
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev)
|
|||
struct kfd_dev *kfd = adev->kfd.dev;
|
||||
unsigned int i;
|
||||
|
||||
if (!kfd)
|
||||
if (!kfd || !kfd->init_complete)
|
||||
return;
|
||||
|
||||
for (i = 0; i < kfd->num_nodes; i++) {
|
||||
|
|
|
|||
|
|
@ -1954,18 +1954,17 @@ static void amdgpu_uid_fini(struct amdgpu_device *adev)
|
|||
adev->uid_info = NULL;
|
||||
}
|
||||
|
||||
static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
|
||||
static void amdgpu_device_init_pcie_links(struct amdgpu_device *adev)
|
||||
{
|
||||
struct pci_dev *parent = adev->pdev;
|
||||
adev->link_dev = adev->pdev;
|
||||
adev->link_partner = pci_upstream_bridge(adev->link_dev);
|
||||
|
||||
/* skip upstream/downstream switches internal to dGPU */
|
||||
while ((parent = pci_upstream_bridge(parent))) {
|
||||
if (parent->vendor == PCI_VENDOR_ID_ATI)
|
||||
continue;
|
||||
break;
|
||||
/* Skip upstream/downstream switches internal to the dGPU. */
|
||||
while (adev->link_partner &&
|
||||
adev->link_partner->vendor == PCI_VENDOR_ID_ATI) {
|
||||
adev->link_dev = adev->link_partner;
|
||||
adev->link_partner = pci_upstream_bridge(adev->link_dev);
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1981,7 +1980,6 @@ static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
|
|||
static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ip_block *ip_block;
|
||||
struct pci_dev *parent;
|
||||
bool total, skip_bios, early_full_gpu_access = false;
|
||||
uint32_t bios_flags;
|
||||
int i, r;
|
||||
|
|
@ -2077,10 +2075,9 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
|
|||
!dev_is_removable(&adev->pdev->dev))
|
||||
adev->flags |= AMD_IS_PX;
|
||||
|
||||
if (!(adev->flags & AMD_IS_APU)) {
|
||||
parent = amdgpu_device_find_parent(adev);
|
||||
adev->has_pr3 = parent ? pci_pr3_present(parent) : false;
|
||||
}
|
||||
if (!(adev->flags & AMD_IS_APU))
|
||||
adev->has_pr3 = adev->link_partner &&
|
||||
pci_pr3_present(adev->link_partner);
|
||||
|
||||
adev->pm.pp_feature = amdgpu_pp_feature_mask;
|
||||
if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS)
|
||||
|
|
@ -3776,6 +3773,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
|
||||
adev->shutdown = false;
|
||||
adev->flags = flags;
|
||||
amdgpu_device_init_pcie_links(adev);
|
||||
|
||||
if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST)
|
||||
adev->asic_type = amdgpu_force_asic_type;
|
||||
|
|
@ -4337,7 +4335,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
|
|||
|
||||
void amdgpu_device_fini_sw(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, idx;
|
||||
int i;
|
||||
bool px;
|
||||
|
||||
amdgpu_device_ip_fini(adev);
|
||||
|
|
@ -4379,11 +4377,9 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
|
|||
if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
|
||||
vga_client_unregister(adev->pdev);
|
||||
|
||||
if (drm_dev_enter(adev_to_drm(adev), &idx)) {
|
||||
|
||||
if (adev->rmmio) {
|
||||
iounmap(adev->rmmio);
|
||||
adev->rmmio = NULL;
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PERF_EVENTS))
|
||||
|
|
@ -5872,11 +5868,9 @@ static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev,
|
|||
*width = PCIE_LNK_WIDTH_UNKNOWN;
|
||||
|
||||
if (amdgpu_device_pcie_dynamic_switching_supported(adev)) {
|
||||
struct pci_dev *parent = amdgpu_device_find_parent(adev);
|
||||
|
||||
if (parent) {
|
||||
*speed = pcie_get_speed_cap(parent);
|
||||
*width = pcie_get_width_cap(parent);
|
||||
if (adev->link_partner) {
|
||||
*speed = pcie_get_speed_cap(adev->link_partner);
|
||||
*width = pcie_get_width_cap(adev->link_partner);
|
||||
}
|
||||
} else {
|
||||
/* use the current speeds rather than max if switching is not supported */
|
||||
|
|
@ -5898,21 +5892,11 @@ static void amdgpu_device_gpu_bandwidth(struct amdgpu_device *adev,
|
|||
enum pci_bus_speed *speed,
|
||||
enum pcie_link_width *width)
|
||||
{
|
||||
struct pci_dev *parent = adev->pdev;
|
||||
|
||||
if (!speed || !width)
|
||||
return;
|
||||
|
||||
/* use the device itself */
|
||||
*speed = pcie_get_speed_cap(adev->pdev);
|
||||
*width = pcie_get_width_cap(adev->pdev);
|
||||
|
||||
/* use the link outside the device */
|
||||
parent = amdgpu_device_find_parent(adev);
|
||||
if (parent) {
|
||||
*speed = pcie_get_speed_cap(parent);
|
||||
*width = pcie_get_width_cap(parent);
|
||||
}
|
||||
*speed = pcie_get_speed_cap(adev->link_dev);
|
||||
*width = pcie_get_width_cap(adev->link_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
#include <linux/pci-p2pdma.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops;
|
||||
|
||||
|
|
@ -100,15 +101,54 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf,
|
|||
pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0)
|
||||
attach->peer2peer = false;
|
||||
|
||||
/*
|
||||
* Only allow P2P while the exporter is active, and keep it active
|
||||
* until detach. With runtime PM disabled take a plain reference so
|
||||
* the put in detach stays balanced.
|
||||
*/
|
||||
if (attach->peer2peer) {
|
||||
struct device *dev = adev_to_drm(adev)->dev;
|
||||
int ret = pm_runtime_get_if_active(dev);
|
||||
|
||||
if (!ret)
|
||||
attach->peer2peer = false;
|
||||
else if (ret < 0)
|
||||
pm_runtime_get_noresume(dev);
|
||||
}
|
||||
|
||||
r = dma_resv_lock(bo->tbo.base.resv, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
goto err_pm_put;
|
||||
|
||||
amdgpu_vm_bo_update_shared(bo);
|
||||
|
||||
dma_resv_unlock(bo->tbo.base.resv);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pm_put:
|
||||
if (attach->peer2peer)
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_dma_buf_detach - &dma_buf_ops.detach implementation
|
||||
*
|
||||
* @dmabuf: DMA-buf where we remove the attachment from
|
||||
* @attach: the attachment to remove
|
||||
*
|
||||
* Drop the runtime PM reference taken in amdgpu_dma_buf_attach().
|
||||
*/
|
||||
static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf,
|
||||
struct dma_buf_attachment *attach)
|
||||
{
|
||||
struct drm_gem_object *obj = dmabuf->priv;
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
|
||||
if (attach->peer2peer)
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -350,6 +390,7 @@ static void amdgpu_dma_buf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map
|
|||
|
||||
const struct dma_buf_ops amdgpu_dmabuf_ops = {
|
||||
.attach = amdgpu_dma_buf_attach,
|
||||
.detach = amdgpu_dma_buf_detach,
|
||||
.pin = amdgpu_dma_buf_pin,
|
||||
.unpin = amdgpu_dma_buf_unpin,
|
||||
.map_dma_buf = amdgpu_dma_buf_map,
|
||||
|
|
|
|||
|
|
@ -535,7 +535,7 @@ static void nbio_v7_9_handle_ras_controller_intr_no_bifring(struct amdgpu_device
|
|||
RAS_CNTLR_INTERRUPT_CLEAR, 1);
|
||||
WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl);
|
||||
|
||||
if (!ras->disable_ras_err_cnt_harvest) {
|
||||
if (ras && !ras->disable_ras_err_cnt_harvest && obj) {
|
||||
/*
|
||||
* clear error status after ras_controller_intr
|
||||
* according to hw team and count ue number
|
||||
|
|
|
|||
|
|
@ -770,10 +770,12 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
|
|||
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
|
||||
q->properties.type)];
|
||||
if (qd && !mqd_mgr->restore_mqd) {
|
||||
pr_debug("restore_mqd not implemented for this GPU\n");
|
||||
pr_debug("restore_mqd not implemented for queue type %d\n",
|
||||
q->properties.type);
|
||||
retval = -EOPNOTSUPP;
|
||||
goto deallocate_vmid;
|
||||
}
|
||||
|
||||
if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
|
||||
retval = allocate_hqd(dqm, q);
|
||||
if (retval)
|
||||
|
|
@ -2250,7 +2252,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
|
|||
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
|
||||
q->properties.type)];
|
||||
if (qd && !mqd_mgr->restore_mqd) {
|
||||
pr_debug("restore_mqd not implemented for this GPU\n");
|
||||
pr_debug("restore_mqd not implemented for queue type %d\n",
|
||||
q->properties.type);
|
||||
retval = -EOPNOTSUPP;
|
||||
goto out_deallocate_doorbell;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
@ -380,6 +380,63 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
|
|||
|
||||
#endif
|
||||
|
||||
static void restore_mqd(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp, const void *mqd_src,
|
||||
const void *ctl_stack_src, const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_compute_mqd *m;
|
||||
|
||||
m = (struct v12_compute_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
/* Update MQD base address to the newly allocated location */
|
||||
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
|
||||
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
|
||||
|
||||
m->cp_hqd_pq_doorbell_control &=
|
||||
~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
|
||||
m->cp_hqd_pq_doorbell_control |=
|
||||
qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp,
|
||||
const void *mqd_src,
|
||||
const void *ctl_stack_src,
|
||||
const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_sdma_mqd *m;
|
||||
|
||||
m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
m->sdmax_rlcx_doorbell_offset =
|
||||
qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
|
||||
struct kfd_node *dev)
|
||||
{
|
||||
|
|
@ -407,6 +464,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
|
|||
mqd->mqd_size = sizeof(struct v12_compute_mqd);
|
||||
mqd->get_wave_state = get_wave_state;
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd;
|
||||
#endif
|
||||
|
|
@ -453,6 +511,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
|
|||
mqd->is_occupied = kfd_is_occupied_sdma;
|
||||
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd_sdma;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
|
||||
ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
@ -641,6 +641,72 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
|
|||
|
||||
#endif
|
||||
|
||||
static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp, const void *mqd_src,
|
||||
const void *ctl_stack_src, const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_1_compute_mqd *m;
|
||||
|
||||
/*
|
||||
* GFX12.1 is multi-XCC capable but this restore handles XCC0 only.
|
||||
* Multi-XCC CRIU restore is currently unreachable because
|
||||
* kfd_criu_restore_queue() validates against unscaled mqd_size.
|
||||
*/
|
||||
if (NUM_XCC(mm->dev->xcc_mask) > 1)
|
||||
pr_warn_once("GFX12.1 multi-XCC CRIU restore not fully supported\n");
|
||||
|
||||
m = (struct v12_1_compute_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) *
|
||||
NUM_XCC(mm->dev->xcc_mask));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
/* Update MQD base address to the newly allocated location */
|
||||
m->cp_mqd_base_addr_lo = lower_32_bits(addr);
|
||||
m->cp_mqd_base_addr_hi = upper_32_bits(addr);
|
||||
|
||||
m->cp_hqd_pq_doorbell_control &=
|
||||
~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
|
||||
m->cp_hqd_pq_doorbell_control |=
|
||||
qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
|
||||
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
static void restore_mqd_sdma_v12_1(struct mqd_manager *mm, void **mqd,
|
||||
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
|
||||
struct queue_properties *qp,
|
||||
const void *mqd_src,
|
||||
const void *ctl_stack_src,
|
||||
const u32 ctl_stack_size)
|
||||
{
|
||||
u64 addr;
|
||||
struct v12_sdma_mqd *m;
|
||||
|
||||
m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
|
||||
addr = mqd_mem_obj->gpu_addr;
|
||||
|
||||
memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
|
||||
memcpy(m, mqd_src, sizeof(*m));
|
||||
|
||||
m->sdmax_rlcx_doorbell_offset =
|
||||
qp->doorbell_off << SDMA0_SDMA_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
|
||||
|
||||
*mqd = m;
|
||||
if (gart_addr)
|
||||
*gart_addr = addr;
|
||||
|
||||
qp->is_active = 0;
|
||||
}
|
||||
|
||||
struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
|
||||
struct kfd_node *dev)
|
||||
{
|
||||
|
|
@ -668,6 +734,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
|
|||
mqd->mqd_size = sizeof(struct v12_1_compute_mqd);
|
||||
mqd->get_wave_state = get_wave_state_v12_1;
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd_v12_1;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd;
|
||||
#endif
|
||||
|
|
@ -714,6 +781,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
|
|||
mqd->is_occupied = kfd_is_occupied_sdma;
|
||||
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
|
||||
mqd->mqd_stride = kfd_mqd_stride;
|
||||
mqd->restore_mqd = restore_mqd_sdma_v12_1;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -285,6 +285,10 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
1 << CP_HQD_IB_CONTROL__IB_EXE_DISABLE__SHIFT;
|
||||
|
||||
/*
|
||||
* The lowest 6 bits of eop_control store the EOP ring size. If
|
||||
* their value is X, the ring size is 2^(X + 1) dwords, or
|
||||
* 2^(X + 3) bytes.
|
||||
*
|
||||
* HW does not clamp this field correctly. Maximum EOP queue size
|
||||
* is constrained by per-SE EOP done signal count, which is 8-bit.
|
||||
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
|
||||
|
|
@ -296,7 +300,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
*
|
||||
*/
|
||||
m->cp_hqd_eop_control = q->eop_ring_buffer_size ?
|
||||
min(0xA, order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
|
||||
min(0xA, order_base_2(q->eop_ring_buffer_size / 8)) : 0;
|
||||
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
|
|
|
|||
|
|
@ -208,6 +208,9 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
mtype << CP_HQD_IB_CONTROL__MTYPE__SHIFT;
|
||||
|
||||
/*
|
||||
* The lowest 6 bits of eop_control store the EOP ring size. If
|
||||
* their value is X, the ring size is 2^(X + 1) dwords, or
|
||||
* 2^(X + 3) bytes.
|
||||
* HW does not clamp this field correctly. Maximum EOP queue size
|
||||
* is constrained by per-SE EOP done signal count, which is 8-bit.
|
||||
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
|
||||
|
|
@ -215,7 +218,7 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
|
|||
* is safe, giving a maximum field value of 0xA.
|
||||
*/
|
||||
m->cp_hqd_eop_control |= q->eop_ring_buffer_size ? min(0xA,
|
||||
order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
|
||||
order_base_2(q->eop_ring_buffer_size / 8)) : 0;
|
||||
m->cp_hqd_eop_base_addr_lo =
|
||||
lower_32_bits(q->eop_ring_buffer_address >> 8);
|
||||
m->cp_hqd_eop_base_addr_hi =
|
||||
|
|
|
|||
|
|
@ -1420,7 +1420,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
|
|||
if (acrtc && state->stream_status[i].plane_count != 0 &&
|
||||
amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
|
||||
irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
|
||||
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
|
||||
if (rc)
|
||||
drm_warn(adev_to_drm(adev), "Failed to %s pflip interrupts\n",
|
||||
enable ? "enable" : "disable");
|
||||
|
|
@ -1444,7 +1444,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
|
|||
/* During gpu-reset we disable and then enable vblank irq, so
|
||||
* don't use amdgpu_irq_get/put() to avoid refcount change.
|
||||
*/
|
||||
if (!dc_interrupt_set(adev->dm.dc, irq_source, enable))
|
||||
if (!amdgpu_dm_irq_set(adev, irq_source, enable))
|
||||
drm_warn(adev_to_drm(adev), "Failed to %sable vblank interrupt\n", enable ? "en" : "dis");
|
||||
|
||||
} else if (acrtc && state->stream_status[i].plane_count != 0) {
|
||||
|
|
|
|||
|
|
@ -552,6 +552,18 @@ struct amdgpu_display_manager {
|
|||
struct common_irq_params
|
||||
vupdate_params[DC_IRQ_SOURCE_VUPDATE6 - DC_IRQ_SOURCE_VUPDATE1 + 1];
|
||||
|
||||
/**
|
||||
* @irq_reg_lock:
|
||||
*
|
||||
* Serializes the read-modify-writes of the HW interrupt control
|
||||
* registers. Several interrupt sources share one register - e.g. the
|
||||
* enable and clear bits of both VSTARTUP (vblank) and VUPDATE_NO_LOCK
|
||||
* live in OTG_GLOBAL_SYNC_STATUS. Therefore, enabling one source must
|
||||
* not race with acking another. Held only across amdgpu_dm_irq_set()
|
||||
* and amdgpu_dm_irq_ack().
|
||||
*/
|
||||
spinlock_t irq_reg_lock;
|
||||
|
||||
/**
|
||||
* @dmub_trace_params:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "amdgpu_dm_psr.h"
|
||||
#include "amdgpu_dm_replay.h"
|
||||
#include "amdgpu_dm_crtc.h"
|
||||
#include "amdgpu_dm_irq.h"
|
||||
#include "amdgpu_dm_plane.h"
|
||||
#include "amdgpu_dm_trace.h"
|
||||
#include "amdgpu_dm_debugfs.h"
|
||||
|
|
@ -91,7 +92,7 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
|
|||
|
||||
irq_source = IRQ_TYPE_VUPDATE + acrtc->otg_inst;
|
||||
|
||||
rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
|
||||
rc = amdgpu_dm_irq_set(adev, irq_source, enable) ? 0 : -EBUSY;
|
||||
|
||||
DRM_DEBUG_VBL("crtc %d - vupdate irq %sabling: r=%d\n",
|
||||
acrtc->crtc_id, enable ? "en" : "dis", rc);
|
||||
|
|
|
|||
|
|
@ -1439,12 +1439,13 @@ void dm_helpers_free_gpu_mem(
|
|||
|
||||
bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable)
|
||||
{
|
||||
struct amdgpu_device *adev = ctx->driver_context;
|
||||
enum dc_irq_source irq_source;
|
||||
bool ret;
|
||||
|
||||
irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
|
||||
|
||||
ret = dc_interrupt_set(ctx->dc, irq_source, enable);
|
||||
ret = amdgpu_dm_irq_set(adev, irq_source, enable);
|
||||
|
||||
DRM_DEBUG_DRIVER("Dmub trace irq %sabling: r=%d\n",
|
||||
enable ? "en" : "dis", ret);
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev)
|
|||
DRM_DEBUG_KMS("DM_IRQ\n");
|
||||
|
||||
spin_lock_init(&adev->dm.irq_handler_list_table_lock);
|
||||
spin_lock_init(&adev->dm.irq_reg_lock);
|
||||
|
||||
adev->dm.irq_wq = alloc_workqueue("amdgpu_dm_irq",
|
||||
WQ_UNBOUND | WQ_HIGHPRI, 0);
|
||||
|
|
@ -530,7 +531,7 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
|
|||
*/
|
||||
for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
|
||||
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
|
||||
dc_interrupt_set(adev->dm.dc, src, false);
|
||||
amdgpu_dm_irq_set(adev, src, false);
|
||||
|
||||
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
|
||||
|
||||
|
|
@ -568,7 +569,7 @@ void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
|
|||
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
|
||||
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
|
||||
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
|
||||
dc_interrupt_set(adev->dm.dc, src, true);
|
||||
amdgpu_dm_irq_set(adev, src, true);
|
||||
}
|
||||
|
||||
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
|
||||
|
|
@ -594,7 +595,7 @@ void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
|
|||
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src];
|
||||
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
|
||||
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
|
||||
dc_interrupt_set(adev->dm.dc, src, true);
|
||||
amdgpu_dm_irq_set(adev, src, true);
|
||||
}
|
||||
|
||||
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
|
||||
|
|
@ -690,6 +691,23 @@ STATIC_IFN_KUNIT void amdgpu_dm_irq_immediate_work(struct amdgpu_device *adev,
|
|||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_irq_immediate_work);
|
||||
|
||||
bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
|
||||
bool enable)
|
||||
{
|
||||
guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
|
||||
|
||||
return dc_interrupt_set(adev->dm.dc, src, enable);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_irq_set);
|
||||
|
||||
void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src)
|
||||
{
|
||||
guard(spinlock_irqsave)(&adev->dm.irq_reg_lock);
|
||||
|
||||
dc_interrupt_ack(adev->dm.dc, src);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_irq_ack);
|
||||
|
||||
/**
|
||||
* amdgpu_dm_irq_handler - Generic DM IRQ handler
|
||||
* @adev: amdgpu base driver device containing the DM device
|
||||
|
|
@ -710,7 +728,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_irq_handler(struct amdgpu_device *adev,
|
|||
entry->src_id,
|
||||
entry->src_data[0]);
|
||||
|
||||
dc_interrupt_ack(adev->dm.dc, src);
|
||||
amdgpu_dm_irq_ack(adev, src);
|
||||
|
||||
/* Call high irq work immediately */
|
||||
amdgpu_dm_irq_immediate_work(adev, src);
|
||||
|
|
@ -750,7 +768,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_hpd_irq_state(struct amdgpu_device *adev,
|
|||
enum dc_irq_source src = amdgpu_dm_hpd_to_dal_irq_source(type);
|
||||
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, src, st);
|
||||
amdgpu_dm_irq_set(adev, src, st);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_set_hpd_irq_state);
|
||||
|
|
@ -785,7 +803,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev,
|
|||
if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed)
|
||||
dc_allow_idle_optimizations(dc, false);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, irq_source, st);
|
||||
amdgpu_dm_irq_set(adev, irq_source, st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -842,7 +860,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_outbox_irq_state(struct amdgpu_device *a
|
|||
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX;
|
||||
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, irq_source, st);
|
||||
amdgpu_dm_irq_set(adev, irq_source, st);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_outbox_irq_state);
|
||||
|
|
@ -870,7 +888,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_set_dmub_trace_irq_state(struct amdgpu_device *ad
|
|||
enum dc_irq_source irq_source = DC_IRQ_SOURCE_DMCUB_OUTBOX0;
|
||||
bool st = (state == AMDGPU_IRQ_STATE_ENABLE);
|
||||
|
||||
dc_interrupt_set(adev->dm.dc, irq_source, st);
|
||||
amdgpu_dm_irq_set(adev, irq_source, st);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_set_dmub_trace_irq_state);
|
||||
|
|
@ -937,9 +955,7 @@ EXPORT_IF_KUNIT(amdgpu_dm_set_irq_funcs);
|
|||
|
||||
void amdgpu_dm_outbox_init(struct amdgpu_device *adev)
|
||||
{
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
DC_IRQ_SOURCE_DMCUB_OUTBOX,
|
||||
true);
|
||||
amdgpu_dm_irq_set(adev, DC_IRQ_SOURCE_DMCUB_OUTBOX, true);
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_outbox_init);
|
||||
|
||||
|
|
@ -962,7 +978,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
|
|||
|
||||
/* First, clear all hpd and hpdrx interrupts */
|
||||
for (i = DC_IRQ_SOURCE_HPD1; i <= DC_IRQ_SOURCE_HPD6RX; i++) {
|
||||
if (!dc_interrupt_set(adev->dm.dc, i, false))
|
||||
if (!amdgpu_dm_irq_set(adev, i, false))
|
||||
drm_err(dev, "Failed to clear hpd(rx) source=%d on init\n",
|
||||
i);
|
||||
}
|
||||
|
|
@ -991,7 +1007,7 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
|
|||
* of dm. Note that only hpd interrupt types are registered with
|
||||
* base driver; hpd_rx types aren't. IOW, amdgpu_irq_get/put on
|
||||
* hpd_rx isn't available. DM currently controls hpd_rx
|
||||
* explicitly with dc_interrupt_set()
|
||||
* explicitly with amdgpu_dm_irq_set()
|
||||
*/
|
||||
if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
|
||||
irq_type = dc_link->irq_source_hpd - DC_IRQ_SOURCE_HPD1;
|
||||
|
|
@ -1000,23 +1016,21 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
|
|||
* and what bios reports as the # of connectors with hpd
|
||||
* sources. Since the # of hpd source types registered
|
||||
* with base driver == mode_info.num_hpd, we have to
|
||||
* fallback to dc_interrupt_set for the remaining types.
|
||||
* fallback to amdgpu_dm_irq_set for the remaining types.
|
||||
*/
|
||||
if (irq_type < adev->mode_info.num_hpd) {
|
||||
if (amdgpu_irq_get(adev, &adev->hpd_irq, irq_type))
|
||||
drm_err(dev, "DM_IRQ: Failed get HPD for source=%d)!\n",
|
||||
dc_link->irq_source_hpd);
|
||||
} else {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd,
|
||||
true);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd_rx,
|
||||
true);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
|
||||
true);
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&iter);
|
||||
|
|
@ -1061,16 +1075,14 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
|
|||
drm_err(dev, "DM_IRQ: Failed put HPD for source=%d!\n",
|
||||
dc_link->irq_source_hpd);
|
||||
} else {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd,
|
||||
false);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
|
||||
dc_interrupt_set(adev->dm.dc,
|
||||
dc_link->irq_source_hpd_rx,
|
||||
false);
|
||||
amdgpu_dm_irq_set(adev, dc_link->irq_source_hpd_rx,
|
||||
false);
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&iter);
|
||||
|
|
|
|||
|
|
@ -89,6 +89,34 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev,
|
|||
enum dc_irq_source irq_source,
|
||||
void *ih_index);
|
||||
|
||||
/**
|
||||
* amdgpu_dm_irq_set - enable or disable a DC interrupt source.
|
||||
*
|
||||
* @adev: AMD DRM device
|
||||
* @src: DC interrupt source to toggle
|
||||
* @enable: true to enable the source, false to disable it
|
||||
*
|
||||
* DM-wide replacement for dc_interrupt_set(). As locking is DM's
|
||||
* responsibility, this is a thin wrapper serializes the underlying
|
||||
* read-modify-write against the other interrupt sources sharing HW control
|
||||
* registers with @src, so DM must never call dc_interrupt_set() directly.
|
||||
*
|
||||
* Returns: true if the source was toggled.
|
||||
*/
|
||||
bool amdgpu_dm_irq_set(struct amdgpu_device *adev, enum dc_irq_source src,
|
||||
bool enable);
|
||||
|
||||
/**
|
||||
* amdgpu_dm_irq_ack - acknowledge a DC interrupt source.
|
||||
*
|
||||
* @adev: AMD DRM device
|
||||
* @src: DC interrupt source to acknowledge
|
||||
*
|
||||
* DM-wide replacement for dc_interrupt_ack(), serialized the same way as
|
||||
* amdgpu_dm_irq_set().
|
||||
*/
|
||||
void amdgpu_dm_irq_ack(struct amdgpu_device *adev, enum dc_irq_source src);
|
||||
|
||||
void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_dm_outbox_init(struct amdgpu_device *adev);
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ static void dm_test_crtc_set_vupdate_irq_no_otg(struct kunit *test)
|
|||
* dm_test_crtc_set_vupdate_irq_dc_busy - Test vupdate irq when DC rejects request
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* With an OTG instance assigned but no DC attached, dc_interrupt_set() returns
|
||||
* With an OTG instance assigned but no DC attached, amdgpu_dm_irq_set() returns
|
||||
* false and the function must report the request as busy (-EBUSY).
|
||||
*/
|
||||
static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
|
||||
|
|
@ -453,12 +453,12 @@ static void dm_test_crtc_set_vupdate_irq_dc_busy(struct kunit *test)
|
|||
acrtc->base.dev = &adev->ddev;
|
||||
acrtc->otg_inst = 0;
|
||||
|
||||
/* adev->dm.dc is NULL, so dc_interrupt_set() returns false. */
|
||||
/* adev->dm.dc is NULL, so amdgpu_dm_irq_set() returns false. */
|
||||
KUNIT_EXPECT_EQ(test,
|
||||
amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, true), -EBUSY);
|
||||
}
|
||||
|
||||
/* Per-source funcs let dc_interrupt_set() succeed without register access. */
|
||||
/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
|
||||
static bool dm_test_vupdate_irq_src_set(struct irq_service *irq_service,
|
||||
const struct irq_source_info *info,
|
||||
bool enable)
|
||||
|
|
@ -477,7 +477,7 @@ static struct irq_source_info_funcs dm_test_vupdate_irq_src_funcs = {
|
|||
.ack = dm_test_vupdate_irq_src_ack,
|
||||
};
|
||||
|
||||
/* A .set that fails so dc_interrupt_set() reports the source as busy. */
|
||||
/* A .set that fails so amdgpu_dm_irq_set() reports the source as busy. */
|
||||
static bool dm_test_vupdate_irq_src_set_busy(struct irq_service *irq_service,
|
||||
const struct irq_source_info *info,
|
||||
bool enable)
|
||||
|
|
@ -519,7 +519,9 @@ static void dm_test_crtc_set_vupdate_irq_enable(struct kunit *test)
|
|||
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
|
||||
|
||||
/* Populate the per-source info table so dc_interrupt_set() succeeds. */
|
||||
/*
|
||||
* Populate the per-source info table so amdgpu_dm_irq_set() succeeds.
|
||||
*/
|
||||
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
|
||||
GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
|
||||
|
|
@ -1018,7 +1020,9 @@ static void dm_test_crtc_enable_vblank_vupdate_busy(struct kunit *test)
|
|||
irqs = kunit_kzalloc(test, sizeof(*irqs), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
|
||||
|
||||
/* Per-source .set fails so dc_interrupt_set() reports the source busy. */
|
||||
/*
|
||||
* Per-source .set fails so amdgpu_dm_irq_set() reports the source busy.
|
||||
*/
|
||||
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
|
||||
GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
|
||||
|
|
|
|||
|
|
@ -2442,17 +2442,21 @@ static void dm_test_is_dp_sink_present_null_priv(struct kunit *test)
|
|||
* dm_test_dmub_outbox_interrupt_control_null_dc - Test outbox irq control with NULL dc
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* dc_interrupt_set() is NULL-safe and returns false when dc is NULL, so the
|
||||
* amdgpu_dm_irq_set() is NULL-safe and returns false when dc is NULL, so the
|
||||
* helper returns false without touching real interrupt hardware.
|
||||
*/
|
||||
static void dm_test_dmub_outbox_interrupt_control_null_dc(struct kunit *test)
|
||||
{
|
||||
struct amdgpu_device *adev;
|
||||
struct dc_context *ctx;
|
||||
|
||||
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, adev);
|
||||
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx);
|
||||
ctx->driver_context = adev;
|
||||
|
||||
/* ctx->dc is NULL → dc_interrupt_set returns false */
|
||||
/* adev->dm.dc is NULL → amdgpu_dm_irq_set returns false */
|
||||
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, true));
|
||||
KUNIT_EXPECT_FALSE(test, dm_helpers_dmub_outbox_interrupt_control(ctx, false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ static bool dm_test_irq_src_ack(struct irq_service *irq_service,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Per-source funcs let dc_interrupt_set() succeed without register access. */
|
||||
/* Per-source funcs let amdgpu_dm_irq_set() succeed without register access. */
|
||||
static struct irq_source_info_funcs dm_test_irq_src_funcs = {
|
||||
.set = dm_test_irq_src_set,
|
||||
.ack = dm_test_irq_src_ack,
|
||||
|
|
@ -290,7 +290,7 @@ static struct dc *dm_test_alloc_dc_with_irq_service(struct kunit *test,
|
|||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, irqs);
|
||||
|
||||
/*
|
||||
* Populate the per-source info table so dc_interrupt_set()/_ack()
|
||||
* Populate the per-source info table so amdgpu_dm_irq_set()/_ack()
|
||||
* succeed without touching hardware registers.
|
||||
*/
|
||||
info = kunit_kzalloc(test, sizeof(*info) * DAL_IRQ_SOURCES_NUMBER,
|
||||
|
|
@ -1227,7 +1227,7 @@ static void dm_test_irq_suspend_empty(struct kunit *test)
|
|||
KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0);
|
||||
|
||||
/*
|
||||
* With no registered handlers the HW dc_interrupt_set() calls are
|
||||
* With no registered handlers the amdgpu_dm_irq_set() calls are
|
||||
* skipped, so suspend must complete without touching the (absent) DC.
|
||||
*/
|
||||
amdgpu_dm_irq_suspend(adev);
|
||||
|
|
@ -1275,11 +1275,11 @@ static void dm_test_irq_resume_late_empty(struct kunit *test)
|
|||
}
|
||||
|
||||
/**
|
||||
* dm_test_irq_suspend_registered - Test suspend reaches the dc_interrupt_set path
|
||||
* dm_test_irq_suspend_registered - Test suspend reaches the irq set path
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* Registers a low-context HPD handler so the handler list is non-empty,
|
||||
* forcing amdgpu_dm_irq_suspend() to call dc_interrupt_set() (NULL-safe with
|
||||
* forcing amdgpu_dm_irq_suspend() to call amdgpu_dm_irq_set() (NULL-safe with
|
||||
* no DC) and flush_work() on the registered handler.
|
||||
*/
|
||||
static void dm_test_irq_suspend_registered(struct kunit *test)
|
||||
|
|
@ -1330,11 +1330,11 @@ static void dm_test_irq_suspend_disables_polling(struct kunit *test)
|
|||
}
|
||||
|
||||
/**
|
||||
* dm_test_irq_resume_early_registered - Test early resume reaches dc_interrupt_set
|
||||
* dm_test_irq_resume_early_registered - Test early resume reaches irq set
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* Registers a low-context HPD RX handler so early resume calls
|
||||
* dc_interrupt_set() for the short-pulse interrupt source.
|
||||
* amdgpu_dm_irq_set() for the short-pulse interrupt source.
|
||||
*/
|
||||
static void dm_test_irq_resume_early_registered(struct kunit *test)
|
||||
{
|
||||
|
|
@ -1358,10 +1358,10 @@ static void dm_test_irq_resume_early_registered(struct kunit *test)
|
|||
}
|
||||
|
||||
/**
|
||||
* dm_test_irq_resume_late_registered - Test late resume reaches dc_interrupt_set
|
||||
* dm_test_irq_resume_late_registered - Test late resume reaches irq set
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* Registers a low-context HPD handler so late resume calls dc_interrupt_set()
|
||||
* Registers a low-context HPD handler so late resume calls amdgpu_dm_irq_set()
|
||||
* for the HPD interrupt source.
|
||||
*/
|
||||
static void dm_test_irq_resume_late_registered(struct kunit *test)
|
||||
|
|
@ -1592,7 +1592,7 @@ static void dm_test_set_crtc_irq_state_enable(struct kunit *test)
|
|||
|
||||
/*
|
||||
* otg_inst >= 0 computes the irq source and reaches the NULL-safe
|
||||
* dc_interrupt_set(); the ips_support branch is skipped (dc == NULL).
|
||||
* amdgpu_dm_irq_set(); the ips_support branch is skipped (dc == NULL).
|
||||
*/
|
||||
acrtc->otg_inst = 3;
|
||||
adev->mode_info.crtcs[0] = acrtc;
|
||||
|
|
@ -1671,8 +1671,8 @@ static void dm_test_set_vupdate_irq_state_enable(struct kunit *test)
|
|||
*
|
||||
* With a non-NULL DC that advertises IPS support and currently allows idle
|
||||
* optimizations, dm_irq_state() must call dc_allow_idle_optimizations() before
|
||||
* dc_interrupt_set(). disable_idle_power_optimizations makes that call a safe
|
||||
* early return, and per-source stub funcs let dc_interrupt_set() succeed.
|
||||
* amdgpu_dm_irq_set(). disable_idle_power_optimizations makes that call a safe
|
||||
* early return, and per-source stub funcs let amdgpu_dm_irq_set() succeed.
|
||||
*/
|
||||
static void dm_test_set_crtc_irq_state_allows_idle(struct kunit *test)
|
||||
{
|
||||
|
|
@ -1891,7 +1891,7 @@ static void dm_test_set_hpd_irq_state_null_dc(struct kunit *test)
|
|||
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
|
||||
|
||||
/* dc_interrupt_set() is a no-op when dc is NULL, so both states
|
||||
/* amdgpu_dm_irq_set() is a no-op when dc is NULL, so both states
|
||||
* return 0 without dereferencing the (absent) DC.
|
||||
*/
|
||||
KUNIT_EXPECT_EQ(test, amdgpu_dm_set_hpd_irq_state(adev, NULL, AMDGPU_HPD_1,
|
||||
|
|
@ -1951,7 +1951,7 @@ static void dm_test_outbox_init_null_dc(struct kunit *test)
|
|||
adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev);
|
||||
|
||||
/* Single dc_interrupt_set() call must be skipped when dc is NULL. */
|
||||
/* Single amdgpu_dm_irq_set() call must be skipped when dc is NULL. */
|
||||
amdgpu_dm_outbox_init(adev);
|
||||
}
|
||||
|
||||
|
|
@ -1969,7 +1969,7 @@ static void dm_test_hpd_init_empty_connectors(struct kunit *test)
|
|||
|
||||
/*
|
||||
* With an empty connector list the per-connector loop is skipped and
|
||||
* the initial clear loop relies on dc_interrupt_set() being a no-op
|
||||
* the initial clear loop relies on amdgpu_dm_irq_set() being a no-op
|
||||
* for a NULL dc, so init must complete without touching the DC.
|
||||
*/
|
||||
amdgpu_dm_hpd_init(adev);
|
||||
|
|
@ -2004,7 +2004,7 @@ static void dm_test_hpd_init_fini_with_connectors(struct kunit *test)
|
|||
|
||||
/*
|
||||
* num_hpd = 0 forces irq_type >= num_hpd so the loop takes the HW
|
||||
* fallback (dc_interrupt_set()) instead of amdgpu_irq_get(); with a
|
||||
* fallback (amdgpu_dm_irq_set()) instead of amdgpu_irq_get(); with a
|
||||
* NULL dc that fallback is a safe no-op.
|
||||
*/
|
||||
adev->mode_info.num_hpd = 0;
|
||||
|
|
@ -2090,7 +2090,7 @@ static void dm_test_hpd_init_fini_irq_ref(struct kunit *test)
|
|||
/*
|
||||
* num_hpd >= 1 makes irq_type (0) < num_hpd, so the loop takes the
|
||||
* amdgpu_irq_get()/amdgpu_irq_put() branch instead of the
|
||||
* dc_interrupt_set() fallback. The mock device has irq.installed ==
|
||||
* amdgpu_dm_irq_set() fallback. The mock device has irq.installed ==
|
||||
* false, so both calls fail early with -ENOENT (logging an error)
|
||||
* without touching the base-driver irq state.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1064,10 +1064,12 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
|
|||
*/
|
||||
unsigned int denom = refresh_hz * 6528;
|
||||
unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
|
||||
uint64_t num = (1000000LL + 2 * stutter_period * refresh_hz) *
|
||||
(100LL + dc->debug.mall_additional_timer_percent);
|
||||
uint64_t tmr_ticks;
|
||||
|
||||
tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
|
||||
(100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
|
||||
denom) - 64LL);
|
||||
tmr_ticks = div_u64(num + denom - 1, denom);
|
||||
tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
|
||||
|
||||
/* In some cases the stutter period is really big (tiny modes) in these
|
||||
* cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
|
||||
|
|
@ -1089,9 +1091,8 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
|
|||
}
|
||||
|
||||
denom *= 2;
|
||||
tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
|
||||
(100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
|
||||
denom) - 64LL);
|
||||
tmr_ticks = div_u64(num + denom - 1, denom);
|
||||
tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
|
||||
}
|
||||
|
||||
/* Copy HW cursor */
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ static void dcn50_initialize_min_clocks(struct dc *dc)
|
|||
* audio corruption. Read current DISPCLK from DENTIST and request the same
|
||||
* freq to ensure that the timing is valid and unchanged.
|
||||
*/
|
||||
clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
|
||||
if (dc->clk_mgr->funcs->get_dispclk_from_dentist)
|
||||
clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
|
||||
}
|
||||
clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
|
||||
clocks->fclk_p_state_change_support = true;
|
||||
|
|
@ -639,7 +640,8 @@ void dcn50_init_hw(struct dc *dc)
|
|||
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
|
||||
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
|
||||
|
||||
dcn50_initialize_min_clocks(dc);
|
||||
if (dc->clk_mgr && dc->clk_mgr->funcs)
|
||||
dcn50_initialize_min_clocks(dc);
|
||||
|
||||
/* On HW init, allow idle optimizations after pipes have been turned off.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -643,7 +643,8 @@ void dcn60_init_hw(struct dc *dc)
|
|||
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
|
||||
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
|
||||
|
||||
dcn401_initialize_min_clocks(dc);
|
||||
if (dc->clk_mgr && dc->clk_mgr->funcs)
|
||||
dcn401_initialize_min_clocks(dc);
|
||||
|
||||
/* On HW init, allow idle optimizations after pipes have been turned off.
|
||||
*
|
||||
|
|
@ -1001,6 +1002,7 @@ static void dcn60_build_hubbub_perfmon_sequence(
|
|||
/**
|
||||
* dcn60_update_probe_status - Set the valid flag on a latched probe result.
|
||||
* @status: result sink whose u was written by the GET BLS step during execute
|
||||
* @probe: current probe state used to determine measurement type and validity
|
||||
*/
|
||||
static void dcn60_update_probe_status(struct dc_probe_status *status)
|
||||
{
|
||||
|
|
@ -1024,6 +1026,7 @@ static void dcn60_update_probe_status(struct dc_probe_status *status)
|
|||
/**
|
||||
* is_probe_measurement_type_for_hubbub - Returns true if the probe type is
|
||||
* served by the hubbub perfmon block on DCN60.
|
||||
* @type: the probe measurement type to classify
|
||||
*/
|
||||
static bool is_probe_measurement_type_for_hubbub(enum dc_probe_type type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2142,6 +2142,7 @@ static void smu_v14_0_2_init_msg_ctl(struct smu_context *smu)
|
|||
static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
||||
void **table)
|
||||
{
|
||||
uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
|
||||
struct gpu_metrics_v1_3 *gpu_metrics =
|
||||
(struct gpu_metrics_v1_3 *)smu_driver_table_ptr(
|
||||
smu, SMU_DRIVER_TABLE_GPU_METRICS);
|
||||
|
|
@ -2171,6 +2172,8 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
|
|||
metrics->Vcn1ActivityPercentage);
|
||||
|
||||
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
|
||||
if (mp1_ver == IP_VERSION(14, 0, 3) && smu->smc_fw_version >= 0x00685000)
|
||||
gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
|
||||
|
||||
if (metrics->AverageGfxActivity <= SMU_14_0_2_BUSY_THRESHOLD)
|
||||
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
|
||||
|
|
|
|||
|
|
@ -7,3 +7,10 @@ kms_hdmi_inject@inject-4k,Fail
|
|||
kms_lease@lease-uevent,Fail
|
||||
msm/msm_mapping@memptrs,Fail
|
||||
msm/msm_mapping@ring,Fail
|
||||
|
||||
# Started failing with v7.3-rc2 backmerge
|
||||
# https://gitlab.freedesktop.org/drm/msm/-/work_items/104
|
||||
kms_cursor_legacy@single-move,Fail
|
||||
kms_cursor_legacy@torture-bo,Fail
|
||||
kms_cursor_legacy@forked-bo,Fail
|
||||
kms_cursor_legacy@torture-move,Fail
|
||||
|
|
|
|||
|
|
@ -1462,10 +1462,12 @@ static int prepare_signaling(struct drm_device *dev,
|
|||
struct dma_fence *fence;
|
||||
struct drm_out_fence_state *f;
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
f = krealloc(*fence_state, sizeof(**fence_state) *
|
||||
(*num_fences + 1), GFP_KERNEL);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
goto err_free_event;
|
||||
|
||||
memset(&f[*num_fences], 0, sizeof(*f));
|
||||
|
||||
|
|
@ -1474,12 +1476,12 @@ static int prepare_signaling(struct drm_device *dev,
|
|||
|
||||
fence = drm_crtc_create_fence(crtc);
|
||||
if (!fence)
|
||||
return -ENOMEM;
|
||||
goto err_free_event;
|
||||
|
||||
ret = setup_out_fence(&f[(*num_fences)++], fence);
|
||||
if (ret) {
|
||||
dma_fence_put(fence);
|
||||
return ret;
|
||||
goto err_free_event;
|
||||
}
|
||||
|
||||
crtc_state->event->base.fence = fence;
|
||||
|
|
@ -1535,6 +1537,11 @@ static int prepare_signaling(struct drm_device *dev,
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_event:
|
||||
drm_event_cancel_free(dev, &crtc_state->event->base);
|
||||
crtc_state->event = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void complete_signaling(struct drm_device *dev,
|
||||
|
|
|
|||
|
|
@ -482,6 +482,9 @@ int gud_plane_atomic_check(struct drm_plane *plane,
|
|||
if (!new_plane_state->visible)
|
||||
return 0;
|
||||
|
||||
if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
|
||||
new_plane_state->ignore_damage_clips = true;
|
||||
|
||||
if (old_plane_state->rotation != new_plane_state->rotation)
|
||||
crtc_state->mode_changed = true;
|
||||
|
||||
|
|
@ -562,8 +565,8 @@ int gud_plane_atomic_check(struct drm_plane *plane,
|
|||
goto out;
|
||||
}
|
||||
|
||||
req->properties[num_properties + i].prop = cpu_to_le16(prop);
|
||||
req->properties[num_properties + i].val = cpu_to_le64(val);
|
||||
req->properties[num_properties].prop = cpu_to_le16(prop);
|
||||
req->properties[num_properties].val = cpu_to_le64(val);
|
||||
num_properties++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -530,18 +530,13 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
|
|||
}
|
||||
|
||||
static void i9xx_cursor_disable_sel_fetch_arm(struct intel_dsb *dsb,
|
||||
struct intel_plane *plane)
|
||||
struct intel_plane *plane,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(plane);
|
||||
enum pipe pipe = plane->pipe;
|
||||
|
||||
/*
|
||||
* Clear this whenever the hardware has selective fetch, not just when
|
||||
* the current state uses it. The cursor may have been enabled with
|
||||
* selective fetch earlier and had its enable bit orphaned when the
|
||||
* feature was switched off.
|
||||
*/
|
||||
if (!HAS_PSR2_SEL_FETCH(display))
|
||||
if (!crtc_state->enable_psr2_sel_fetch)
|
||||
return;
|
||||
|
||||
intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), 0);
|
||||
|
|
@ -591,7 +586,7 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_dsb *dsb,
|
|||
if (crtc_state->enable_psr2_su_region_et)
|
||||
wa_16021440873(dsb, plane, crtc_state, plane_state);
|
||||
else
|
||||
i9xx_cursor_disable_sel_fetch_arm(dsb, plane);
|
||||
i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -700,7 +695,7 @@ static void i9xx_cursor_update_arm(struct intel_dsb *dsb,
|
|||
if (plane_state)
|
||||
i9xx_cursor_update_sel_fetch_arm(dsb, plane, crtc_state, plane_state);
|
||||
else
|
||||
i9xx_cursor_disable_sel_fetch_arm(dsb, plane);
|
||||
i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
|
||||
|
||||
if (plane->cursor.base != base ||
|
||||
plane->cursor.size != fbc_ctl ||
|
||||
|
|
|
|||
|
|
@ -426,12 +426,15 @@ calc_allowed_config_filter(struct intel_dp_link_caps *link_caps,
|
|||
const struct intel_dp_link_config *forced_params)
|
||||
{
|
||||
struct intel_dp_link_caps_filter allowed_configs = INTEL_DP_LINK_CAPS_FILTER_NONE;
|
||||
struct intel_display *display = to_intel_display(link_caps->dp);
|
||||
struct intel_dp_link_caps_order order = bw_desc_config_order();
|
||||
struct intel_dp_link_caps_iter iter;
|
||||
struct intel_dp_link_config config;
|
||||
|
||||
iter_start(&iter, link_caps, order, enabled_configs);
|
||||
for_each_dp_link_config(&iter, &config) {
|
||||
int config_idx;
|
||||
|
||||
if (forced_params->rate &&
|
||||
forced_params->rate != config.rate)
|
||||
continue;
|
||||
|
|
@ -446,7 +449,11 @@ calc_allowed_config_filter(struct intel_dp_link_caps *link_caps,
|
|||
if (config.lane_count > max_limits->lane_count)
|
||||
continue;
|
||||
|
||||
allowed_configs.config_mask |= BIT(iter_pos_to_idx(link_caps, order, iter.pos));
|
||||
config_idx = iter_pos_to_idx(link_caps, order, iter.pos);
|
||||
if (drm_WARN_ON(display->drm, config_idx < 0))
|
||||
continue;
|
||||
|
||||
allowed_configs.config_mask |= BIT(config_idx);
|
||||
}
|
||||
intel_dp_link_caps_iter_end(&iter);
|
||||
|
||||
|
|
|
|||
|
|
@ -879,18 +879,13 @@ skl_plane_disable_arm(struct intel_dsb *dsb,
|
|||
}
|
||||
|
||||
static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
|
||||
struct intel_plane *plane)
|
||||
struct intel_plane *plane,
|
||||
const struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_display *display = to_intel_display(plane);
|
||||
enum pipe pipe = plane->pipe;
|
||||
|
||||
/*
|
||||
* Clear this whenever the hardware has selective fetch, not just when
|
||||
* the current state uses it. The plane may have been enabled with
|
||||
* selective fetch earlier and had its enable bit orphaned when the
|
||||
* feature was switched off.
|
||||
*/
|
||||
if (!HAS_PSR2_SEL_FETCH(display))
|
||||
if (!crtc_state->enable_psr2_sel_fetch)
|
||||
return;
|
||||
|
||||
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0);
|
||||
|
|
@ -926,7 +921,7 @@ icl_plane_disable_arm(struct intel_dsb *dsb,
|
|||
|
||||
skl_write_plane_wm(dsb, plane, crtc_state);
|
||||
|
||||
icl_plane_disable_sel_fetch_arm(dsb, plane);
|
||||
icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
|
||||
|
||||
if (plane_has_normalizer(plane))
|
||||
intel_de_write_dsb(display, dsb,
|
||||
|
|
@ -1646,7 +1641,7 @@ static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
|
|||
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
|
||||
SEL_FETCH_PLANE_CTL_ENABLE);
|
||||
else
|
||||
icl_plane_disable_sel_fetch_arm(dsb, plane);
|
||||
icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
|
@ -765,7 +766,7 @@ int ls7a1000_cursor_plane_init(struct drm_device *ddev,
|
|||
|
||||
drm_plane_helper_add(plane, &ls7a1000_cursor_plane_helper_funcs);
|
||||
|
||||
return 0;
|
||||
return drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_COVERAGE));
|
||||
}
|
||||
|
||||
int ls7a2000_cursor_plane_init(struct drm_device *ddev,
|
||||
|
|
@ -790,5 +791,5 @@ int ls7a2000_cursor_plane_init(struct drm_device *ddev,
|
|||
|
||||
drm_plane_helper_add(plane, &ls7a2000_cursor_plane_helper_funcs);
|
||||
|
||||
return 0;
|
||||
return drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_COVERAGE));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,6 @@ quiet_cmd_headergen = GENHDR $@
|
|||
cmd_headergen = mkdir -p $(obj)/generated && $(PYTHON3) $(src)/registers/gen_header.py \
|
||||
$(headergen-opts) --rnn $(src)/registers --xml $< c-defines > $@
|
||||
|
||||
# TODO how to do this for a2xx/a5xx which have different .xml arg?
|
||||
quiet_cmd_headergen_json = GENHDRJSN $@
|
||||
cmd_headergen_json = mkdir -p $(obj)/generated && $(PYTHON3) $(src)/registers/gen_header.py \
|
||||
$(headergen-opts) --rnn $(src)/registers --xml $(filter %.xml,$^) perfcntrs --json $< > $@
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ static int a6xx_gmu_start(struct a6xx_gmu *gmu)
|
|||
gmu_write(gmu, REG_A6XX_GMU_CM3_SYSRESET, 0);
|
||||
|
||||
ret = gmu_poll_timeout(gmu, REG_A6XX_GMU_CM3_FW_INIT_RESULT, val,
|
||||
(val & mask) == reset_val, 100, 10000);
|
||||
(val & mask) == reset_val, 100, 100000);
|
||||
|
||||
if (ret)
|
||||
DRM_DEV_ERROR(gmu->dev, "GMU firmware initialization timed out\n");
|
||||
|
|
|
|||
|
|
@ -23,9 +23,15 @@ static u64 a6xx_gmu_get_timestamp(struct msm_gpu *gpu)
|
|||
u64 count_hi, count_lo, temp;
|
||||
|
||||
do {
|
||||
count_hi = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_H);
|
||||
count_lo = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_L);
|
||||
temp = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_H);
|
||||
if (adreno_is_a750_family(adreno_gpu)) {
|
||||
count_hi = gmu_read(&a6xx_gpu->gmu, REG_A7XX_GMU_CX_AO_COUNTER_H);
|
||||
count_lo = gmu_read(&a6xx_gpu->gmu, REG_A7XX_GMU_CX_AO_COUNTER_L);
|
||||
temp = gmu_read(&a6xx_gpu->gmu, REG_A7XX_GMU_CX_AO_COUNTER_H);
|
||||
} else {
|
||||
count_hi = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_H);
|
||||
count_lo = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_L);
|
||||
temp = gmu_read(&a6xx_gpu->gmu, REG_A6XX_GMU_ALWAYS_ON_COUNTER_H);
|
||||
}
|
||||
} while (unlikely(count_hi != temp));
|
||||
|
||||
return (count_hi << 32) | count_lo;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ MODULE_PARM_DESC(disable_acd, "Forcefully disable GPU ACD");
|
|||
module_param_unsafe(disable_acd, bool, 0400);
|
||||
|
||||
static bool skip_gpu;
|
||||
MODULE_PARM_DESC(no_gpu, "Disable GPU driver register (0=enable GPU driver register (default), 1=skip GPU driver register");
|
||||
MODULE_PARM_DESC(skip_gpu, "Disable GPU driver register (0=enable GPU driver register (default), 1=skip GPU driver register");
|
||||
module_param(skip_gpu, bool, 0400);
|
||||
|
||||
extern const struct adreno_gpulist a2xx_gpulist;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* We need PAS to be able to load the firmware */
|
||||
if (!qcom_pas_is_available()) {
|
||||
DRM_DEV_ERROR(dev, "PAS is not available\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ret = of_reserved_mem_region_to_resource(np, 0, &r);
|
||||
if (ret) {
|
||||
zap_available = false;
|
||||
|
|
@ -170,18 +176,11 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
|
|||
int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid)
|
||||
{
|
||||
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
|
||||
struct platform_device *pdev = gpu->pdev;
|
||||
|
||||
/* Short cut if we determine the zap shader isn't available/needed */
|
||||
if (!zap_available)
|
||||
return -ENODEV;
|
||||
|
||||
/* We need PAS to be able to load the firmware */
|
||||
if (!qcom_pas_is_available()) {
|
||||
DRM_DEV_ERROR(&pdev->dev, "PAS is not available\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
return zap_shader_load_mdt(gpu, adreno_gpu->info->zapfw, pasid);
|
||||
}
|
||||
|
||||
|
|
@ -1262,6 +1261,8 @@ void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu)
|
|||
for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++)
|
||||
release_firmware(adreno_gpu->fw[i]);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(&gpu->pdev->dev);
|
||||
|
||||
if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev))
|
||||
pm_runtime_disable(&priv->gpu_pdev->dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx)
|
|||
ctx->pending_intf_flush_mask = 0;
|
||||
ctx->pending_wb_flush_mask = 0;
|
||||
ctx->pending_cwb_flush_mask = 0;
|
||||
ctx->pending_periph_flush_mask = 0;
|
||||
ctx->pending_merge_3d_flush_mask = 0;
|
||||
ctx->pending_dsc_flush_mask = 0;
|
||||
ctx->pending_cdm_flush_mask = 0;
|
||||
|
|
|
|||
|
|
@ -756,6 +756,7 @@ enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp,
|
|||
struct msm_dp_link_info *link_info;
|
||||
u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0;
|
||||
int mode_pclk_khz = mode->clock;
|
||||
int link_pclk_khz;
|
||||
bool is_yuv_420;
|
||||
|
||||
if (!dp || !mode_pclk_khz || !dp->connector) {
|
||||
|
|
@ -775,6 +776,8 @@ enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp,
|
|||
if (is_yuv_420 && !msm_dp_display->panel->vsc_sdp_supported)
|
||||
return MODE_NO_420;
|
||||
|
||||
link_pclk_khz = is_yuv_420 ? mode_pclk_khz / 2 : mode_pclk_khz;
|
||||
|
||||
if (is_yuv_420 || msm_dp_display->wide_bus_supported)
|
||||
mode_pclk_khz /= 2;
|
||||
|
||||
|
|
@ -786,9 +789,9 @@ enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp,
|
|||
mode_bpp = default_bpp;
|
||||
|
||||
mode_bpp = msm_dp_panel_get_mode_bpp(msm_dp_display->panel,
|
||||
mode_bpp, mode_pclk_khz);
|
||||
mode_bpp, link_pclk_khz);
|
||||
|
||||
mode_rate_khz = mode_pclk_khz * mode_bpp;
|
||||
mode_rate_khz = link_pclk_khz * mode_bpp;
|
||||
supported_rate_khz = link_info->num_lanes * link_info->rate * 8;
|
||||
|
||||
if (mode_rate_khz > supported_rate_khz)
|
||||
|
|
@ -1458,6 +1461,20 @@ void msm_dp_display_atomic_disable(struct msm_dp *dp)
|
|||
|
||||
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
|
||||
|
||||
/*
|
||||
* If .atomic_enable() bailed out - link training failure is the common
|
||||
* case - the mainlink was never brought up and ->power_on stayed false.
|
||||
* Driving the PUSH_IDLE pattern into a controller that was never
|
||||
* enabled times out, and .atomic_post_disable() then drops the
|
||||
* controller's runtime-PM reference without tearing the PHY back down,
|
||||
* because msm_dp_display_disable() returns early on !power_on. On
|
||||
* glymur (Snapdragon X2 Elite) that combination is answered by a
|
||||
* TrustZone-level SOCCP/ADSP force-stop and a silent SoC reset.
|
||||
* There is nothing to push idle, so leave it alone.
|
||||
*/
|
||||
if (!dp->power_on)
|
||||
return;
|
||||
|
||||
msm_dp_ctrl_push_idle(msm_dp_display->ctrl);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ struct msm_dsi_host {
|
|||
struct clk *dsi_pll_pixel_clk;
|
||||
|
||||
unsigned long byte_clk_rate;
|
||||
unsigned long byte_intf_clk_rate;
|
||||
bool byte_intf_clk_div_2;
|
||||
unsigned long pixel_clk_rate;
|
||||
unsigned long esc_clk_rate;
|
||||
|
||||
|
|
@ -382,8 +382,20 @@ int msm_dsi_runtime_resume(struct device *dev)
|
|||
|
||||
int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host)
|
||||
{
|
||||
unsigned long byte_intf_clk_rate;
|
||||
long rounded_byte_clk_rate;
|
||||
int ret;
|
||||
|
||||
rounded_byte_clk_rate = clk_round_rate(msm_host->byte_clk,
|
||||
msm_host->byte_clk_rate);
|
||||
if (rounded_byte_clk_rate < 0) {
|
||||
pr_err("%s: failed to round byte clock rate, %ld\n",
|
||||
__func__, rounded_byte_clk_rate);
|
||||
return rounded_byte_clk_rate;
|
||||
}
|
||||
|
||||
msm_host->byte_clk_rate = rounded_byte_clk_rate;
|
||||
|
||||
DBG("Set clk rates: pclk=%lu, byteclk=%lu",
|
||||
msm_host->pixel_clk_rate, msm_host->byte_clk_rate);
|
||||
|
||||
|
|
@ -401,7 +413,11 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host)
|
|||
}
|
||||
|
||||
if (msm_host->byte_intf_clk) {
|
||||
ret = clk_set_rate(msm_host->byte_intf_clk, msm_host->byte_intf_clk_rate);
|
||||
byte_intf_clk_rate = msm_host->byte_clk_rate;
|
||||
if (msm_host->byte_intf_clk_div_2)
|
||||
byte_intf_clk_rate /= 2;
|
||||
|
||||
ret = clk_set_rate(msm_host->byte_intf_clk, byte_intf_clk_rate);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to set rate byte intf clk, %d\n",
|
||||
__func__, ret);
|
||||
|
|
@ -669,24 +685,12 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
|
|||
|
||||
int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi)
|
||||
{
|
||||
long rounded_byte_clk_rate;
|
||||
|
||||
if (!msm_host->mode) {
|
||||
pr_err("%s: mode not set\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dsi_calc_pclk(msm_host, is_bonded_dsi);
|
||||
|
||||
rounded_byte_clk_rate = clk_round_rate(msm_host->byte_clk,
|
||||
msm_host->byte_clk_rate);
|
||||
if (rounded_byte_clk_rate < 0) {
|
||||
pr_err("%s: failed to round byte clock rate, %ld\n",
|
||||
__func__, rounded_byte_clk_rate);
|
||||
return rounded_byte_clk_rate;
|
||||
}
|
||||
|
||||
msm_host->byte_clk_rate = rounded_byte_clk_rate;
|
||||
msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2495,9 +2499,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host,
|
|||
goto unlock_ret;
|
||||
}
|
||||
|
||||
msm_host->byte_intf_clk_rate = msm_host->byte_clk_rate;
|
||||
if (phy_shared_timings->byte_intf_clk_div_2)
|
||||
msm_host->byte_intf_clk_rate /= 2;
|
||||
msm_host->byte_intf_clk_div_2 = phy_shared_timings->byte_intf_clk_div_2;
|
||||
|
||||
msm_dsi_sfpb_config(msm_host, true);
|
||||
|
||||
|
|
|
|||
|
|
@ -168,13 +168,13 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
|
|||
|
||||
ret = msm_hdmi_phy_resource_enable(phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_pm_disable;
|
||||
|
||||
ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev, "couldn't init PLL\n");
|
||||
msm_hdmi_phy_resource_disable(phy);
|
||||
return ret;
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
msm_hdmi_phy_resource_disable(phy);
|
||||
|
|
@ -182,6 +182,10 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, phy);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pm_disable:
|
||||
pm_runtime_disable(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void msm_hdmi_phy_remove(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (1=on (default), 0=disab
|
|||
module_param(modeset, bool, 0600);
|
||||
|
||||
static bool separate_gpu_kms;
|
||||
MODULE_PARM_DESC(separate_gpu_drm, "Use separate DRM device for the GPU (0=single DRM device for both GPU and display (default), 1=two DRM devices)");
|
||||
MODULE_PARM_DESC(separate_gpu_kms, "Use separate DRM device for the GPU (0=single DRM device for both GPU and display (default), 1=two DRM devices)");
|
||||
module_param(separate_gpu_kms, bool, 0400);
|
||||
|
||||
DECLARE_FAULT_ATTR(fail_gem_alloc);
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper,
|
|||
helper->fb = buffer->fb;
|
||||
|
||||
fbi->fbops = &msm_fb_ops;
|
||||
fbi->flags |= FBINFO_VIRTFB; /* system memory */
|
||||
|
||||
drm_fb_helper_fill_info(fbi, helper, sizes);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ struct msm_gem_vm {
|
|||
/** @base: Inherit from drm_gpuvm. */
|
||||
struct drm_gpuvm base;
|
||||
|
||||
/** @rcu: RCU-delayed free so an exported sched fence->sched stays valid. */
|
||||
struct rcu_head rcu;
|
||||
|
||||
/**
|
||||
* @sched: Scheduler used for asynchronous VM_BIND request.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ msm_gem_vm_free(struct drm_gpuvm *gpuvm)
|
|||
dma_fence_put(vm->last_fence);
|
||||
put_pid(vm->pid);
|
||||
kfree(vm->log);
|
||||
kfree(vm);
|
||||
kfree_rcu(vm, rcu);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -140,5 +140,5 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring)
|
|||
|
||||
msm_gem_kernel_put(ring->bo, ring->gpu->vm);
|
||||
|
||||
kfree(ring);
|
||||
kfree_rcu(ring, rcu);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ struct msm_ringbuffer {
|
|||
/*
|
||||
* The job scheduler for this ring.
|
||||
*/
|
||||
struct rcu_head rcu;
|
||||
struct drm_gpu_scheduler sched;
|
||||
bool sched_initialized;
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,8 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
|
|||
<reg32 offset="0x1f9f0" name="GMU_BOOT_KMD_LM_HANDSHAKE"/>
|
||||
<reg32 offset="0x1f957" name="GMU_LLM_GLM_SLEEP_CTRL"/>
|
||||
<reg32 offset="0x1f958" name="GMU_LLM_GLM_SLEEP_STATUS"/>
|
||||
<reg32 offset="0x1f880" name="GMU_CX_AO_COUNTER_L" variants="A7XX"/>
|
||||
<reg32 offset="0x1f881" name="GMU_CX_AO_COUNTER_H" variants="A7XX"/>
|
||||
<reg32 offset="0x1f888" name="GMU_ALWAYS_ON_COUNTER_L" variants="A6XX-A7XX"/>
|
||||
<reg32 offset="0x1f840" name="GMU_ALWAYS_ON_COUNTER_L" variants="A8XX-"/>
|
||||
<reg32 offset="0x1f889" name="GMU_ALWAYS_ON_COUNTER_H" variants="A6XX-A7XX"/>
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ r535_fbsr_resume(struct nvkm_gsp *gsp)
|
|||
}
|
||||
|
||||
static int
|
||||
r535_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime)
|
||||
r535_fbsr_suspend(struct nvkm_gsp *gsp)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &gsp->subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
|
|
|
|||
|
|
@ -1749,7 +1749,7 @@ r535_gsp_fini(struct nvkm_gsp *gsp, enum nvkm_suspend_state suspend)
|
|||
sr->sysmemAddrOfSuspendResumeData = gsp->sr.radix3.lvl0.addr;
|
||||
sr->sizeOfSuspendResumeData = len;
|
||||
|
||||
ret = rm->api->fbsr->suspend(gsp, suspend == NVKM_RUNTIME_SUSPEND);
|
||||
ret = rm->api->fbsr->suspend(gsp);
|
||||
if (ret) {
|
||||
nvkm_gsp_mem_dtor(&gsp->sr.meta);
|
||||
nvkm_gsp_radix3_dtor(gsp, &gsp->sr.radix3);
|
||||
|
|
@ -1761,8 +1761,12 @@ r535_gsp_fini(struct nvkm_gsp *gsp, enum nvkm_suspend_state suspend)
|
|||
* TODO: Debug the GSP firmware / RPC handling to find out why
|
||||
* without this Turing (but none of the other architectures)
|
||||
* ends up resetting all channels after resume.
|
||||
* Additionally, runtime suspend on other architectures quickly
|
||||
* becomes unreliable without this sleep. If you're experiencing
|
||||
* issues with runtime suspend, try bumping this delay up and
|
||||
* sending a patch if it fixes your GPU.
|
||||
*/
|
||||
msleep(50);
|
||||
msleep(200);
|
||||
}
|
||||
|
||||
ret = r535_gsp_rpc_unloading_guest_driver(gsp, suspend);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ r570_fbsr_resume(struct nvkm_gsp *gsp)
|
|||
}
|
||||
|
||||
static int
|
||||
r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size, bool runtime)
|
||||
r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size)
|
||||
{
|
||||
NV2080_CTRL_INTERNAL_FBSR_INIT_PARAMS *ctrl;
|
||||
struct nvkm_gsp_object memlist;
|
||||
|
|
@ -81,7 +81,7 @@ r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size, bool runtim
|
|||
ctrl->hClient = gsp->internal.client.object.handle;
|
||||
ctrl->hSysMem = memlist.handle;
|
||||
ctrl->sysmemAddrOfSuspendResumeData = gsp->sr.meta.addr;
|
||||
ctrl->bEnteringGcoffState = runtime ? 1 : 0;
|
||||
ctrl->bEnteringGcoffState = 0;
|
||||
|
||||
ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
|
||||
if (ret)
|
||||
|
|
@ -92,7 +92,7 @@ r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size, bool runtim
|
|||
}
|
||||
|
||||
static int
|
||||
r570_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime)
|
||||
r570_fbsr_suspend(struct nvkm_gsp *gsp)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &gsp->subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
|
|
@ -133,7 +133,7 @@ r570_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime)
|
|||
return ret;
|
||||
|
||||
/* Initialise FBSR on RM. */
|
||||
ret = r570_fbsr_init(gsp, &gsp->sr.fbsr, size, runtime);
|
||||
ret = r570_fbsr_init(gsp, &gsp->sr.fbsr, size);
|
||||
if (ret) {
|
||||
nvkm_gsp_sg_free(device, &gsp->sr.fbsr);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -207,7 +207,8 @@ r570_gsp_set_rmargs(struct nvkm_gsp *gsp, bool resume)
|
|||
args->srInitArguments.bInPMTransition = 0;
|
||||
} else {
|
||||
args->srInitArguments.oldLevel = NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_3;
|
||||
args->srInitArguments.flags = 0;
|
||||
args->srInitArguments.flags =
|
||||
GPU_STATE_FLAGS_PRESERVING | GPU_STATE_FLAGS_PM_TRANSITION;
|
||||
args->srInitArguments.bInPMTransition = 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -523,6 +523,14 @@ typedef struct
|
|||
|
||||
#define NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_3 (0x00000003U)
|
||||
|
||||
#define GPU_STATE_FLAGS_PRESERVING BIT(0) // GPU state is preserved
|
||||
#define GPU_STATE_FLAGS_VGA_TRANSITION BIT(1) // To be used with GPU_STATE_FLAGS_PRESERVING.
|
||||
#define GPU_STATE_FLAGS_PM_TRANSITION BIT(2) // To be used with GPU_STATE_FLAGS_PRESERVING.
|
||||
#define GPU_STATE_FLAGS_PM_SUSPEND BIT(3)
|
||||
#define GPU_STATE_FLAGS_PM_HIBERNATE BIT(4)
|
||||
#define GPU_STATE_FLAGS_GC6_TRANSITION BIT(5) // To be used with GPU_STATE_FLAGS_PRESERVING.
|
||||
#define GPU_STATE_FLAGS_FAST_UNLOAD BIT(6) // Used during windows restart, skips stateDestroy steps
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Magic for verification by secure ucode
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ struct nvkm_rm_api {
|
|||
} *device;
|
||||
|
||||
const struct nvkm_rm_api_fbsr {
|
||||
int (*suspend)(struct nvkm_gsp *, bool runtime);
|
||||
int (*suspend)(struct nvkm_gsp *);
|
||||
void (*resume)(struct nvkm_gsp *);
|
||||
} *fbsr;
|
||||
|
||||
|
|
|
|||
|
|
@ -559,9 +559,10 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
|
|||
*/
|
||||
smp_wmb();
|
||||
|
||||
spin_lock(&entity->lock);
|
||||
spsc_queue_pop(&entity->job_queue);
|
||||
|
||||
drm_sched_rq_pop_entity(entity);
|
||||
spin_unlock(&entity->lock);
|
||||
|
||||
/* Jobs and entities might have different lifecycles. Since we're
|
||||
* removing the job from the entities queue, set the jobs entity pointer
|
||||
|
|
@ -647,6 +648,9 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
|
|||
* Make sure to set the submit_ts first, to avoid a race.
|
||||
*/
|
||||
sched_job->submit_ts = submit_ts = ktime_get();
|
||||
|
||||
spin_lock(&entity->lock);
|
||||
|
||||
first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node);
|
||||
|
||||
/* first job wakes up scheduler */
|
||||
|
|
@ -657,5 +661,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
|
|||
if (sched)
|
||||
drm_sched_wakeup(sched);
|
||||
}
|
||||
|
||||
spin_unlock(&entity->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sched_entity_push_job);
|
||||
|
|
|
|||
|
|
@ -257,19 +257,17 @@ static ktime_t drm_sched_entity_get_job_ts(struct drm_sched_entity *entity)
|
|||
struct drm_gpu_scheduler *
|
||||
drm_sched_rq_add_entity(struct drm_sched_entity *entity, ktime_t ts)
|
||||
{
|
||||
struct drm_sched_rq *rq = entity->rq;
|
||||
struct drm_gpu_scheduler *sched;
|
||||
struct drm_sched_rq *rq;
|
||||
|
||||
/* Add the entity to the run queue */
|
||||
spin_lock(&entity->lock);
|
||||
if (entity->stopped) {
|
||||
spin_unlock(&entity->lock);
|
||||
lockdep_assert_held(&entity->lock);
|
||||
|
||||
if (entity->stopped) {
|
||||
DRM_ERROR("Trying to push to a killed entity\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rq = entity->rq;
|
||||
spin_lock(&rq->lock);
|
||||
sched = rq->sched;
|
||||
|
||||
|
|
@ -289,7 +287,6 @@ drm_sched_rq_add_entity(struct drm_sched_entity *entity, ktime_t ts)
|
|||
drm_sched_rq_update_fifo_locked(entity, rq, ts);
|
||||
|
||||
spin_unlock(&rq->lock);
|
||||
spin_unlock(&entity->lock);
|
||||
|
||||
return sched;
|
||||
}
|
||||
|
|
@ -343,16 +340,17 @@ drm_sched_rq_next_rr_ts(struct drm_sched_rq *rq,
|
|||
*/
|
||||
void drm_sched_rq_pop_entity(struct drm_sched_entity *entity)
|
||||
{
|
||||
struct drm_sched_rq *rq = entity->rq;
|
||||
struct drm_sched_job *next_job;
|
||||
struct drm_sched_rq *rq;
|
||||
|
||||
lockdep_assert_held(&entity->lock);
|
||||
|
||||
spin_lock(&rq->lock);
|
||||
|
||||
/*
|
||||
* Update the entity's location in the min heap according to
|
||||
* the timestamp of the next job, if any.
|
||||
*/
|
||||
spin_lock(&entity->lock);
|
||||
rq = entity->rq;
|
||||
spin_lock(&rq->lock);
|
||||
next_job = drm_sched_entity_queue_peek(entity);
|
||||
if (next_job) {
|
||||
ktime_t ts;
|
||||
|
|
@ -375,8 +373,8 @@ void drm_sched_rq_pop_entity(struct drm_sched_entity *entity)
|
|||
drm_sched_entity_save_vruntime(entity, min_vruntime);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&rq->lock);
|
||||
spin_unlock(&entity->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1434,7 +1434,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
|
|||
|
||||
if (ttm_tt_is_populated(tt)) {
|
||||
ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
|
||||
if (!ret) {
|
||||
if (ret > 0) {
|
||||
spin_lock(&bdev->lru_lock);
|
||||
ttm_resource_del_bulk_move_unevictable(bo->resource, bo);
|
||||
ttm_resource_move_to_lru_tail(bo->resource);
|
||||
|
|
|
|||
|
|
@ -1188,7 +1188,7 @@ int vc4_kms_load(struct drm_device *dev)
|
|||
|
||||
drm_mode_config_reset(dev);
|
||||
|
||||
drm_kms_helper_poll_init(dev);
|
||||
drmm_kms_helper_poll_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
|
|
@ -267,6 +268,7 @@ struct drm_plane *vs_cursor_plane_init(struct drm_device *drm_dev,
|
|||
return plane;
|
||||
|
||||
drm_plane_helper_add(plane, &vs_cursor_plane_helper_funcs);
|
||||
drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_COVERAGE));
|
||||
|
||||
return plane;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,82 +10,50 @@
|
|||
#include "vs_dc_top_regs.h"
|
||||
#include "vs_hwdb.h"
|
||||
|
||||
static const u32 vs_formats_array_no_yuv444[] = {
|
||||
static const u32 vs_primary_formats_array_no_yuv444[] = {
|
||||
DRM_FORMAT_XRGB4444,
|
||||
DRM_FORMAT_XBGR4444,
|
||||
DRM_FORMAT_RGBX4444,
|
||||
DRM_FORMAT_BGRX4444,
|
||||
DRM_FORMAT_ARGB4444,
|
||||
DRM_FORMAT_ABGR4444,
|
||||
DRM_FORMAT_RGBA4444,
|
||||
DRM_FORMAT_BGRA4444,
|
||||
DRM_FORMAT_XRGB1555,
|
||||
DRM_FORMAT_XBGR1555,
|
||||
DRM_FORMAT_RGBX5551,
|
||||
DRM_FORMAT_BGRX5551,
|
||||
DRM_FORMAT_ARGB1555,
|
||||
DRM_FORMAT_ABGR1555,
|
||||
DRM_FORMAT_RGBA5551,
|
||||
DRM_FORMAT_BGRA5551,
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_BGR565,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_XBGR8888,
|
||||
DRM_FORMAT_RGBX8888,
|
||||
DRM_FORMAT_BGRX8888,
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_RGBA8888,
|
||||
DRM_FORMAT_BGRA8888,
|
||||
DRM_FORMAT_ARGB2101010,
|
||||
DRM_FORMAT_ABGR2101010,
|
||||
DRM_FORMAT_RGBA1010102,
|
||||
DRM_FORMAT_BGRA1010102,
|
||||
/* TODO: non-RGB formats */
|
||||
};
|
||||
|
||||
static const u32 vs_formats_array_with_yuv444[] = {
|
||||
static const u32 vs_primary_formats_array_with_yuv444[] = {
|
||||
DRM_FORMAT_XRGB4444,
|
||||
DRM_FORMAT_XBGR4444,
|
||||
DRM_FORMAT_RGBX4444,
|
||||
DRM_FORMAT_BGRX4444,
|
||||
DRM_FORMAT_ARGB4444,
|
||||
DRM_FORMAT_ABGR4444,
|
||||
DRM_FORMAT_RGBA4444,
|
||||
DRM_FORMAT_BGRA4444,
|
||||
DRM_FORMAT_XRGB1555,
|
||||
DRM_FORMAT_XBGR1555,
|
||||
DRM_FORMAT_RGBX5551,
|
||||
DRM_FORMAT_BGRX5551,
|
||||
DRM_FORMAT_ARGB1555,
|
||||
DRM_FORMAT_ABGR1555,
|
||||
DRM_FORMAT_RGBA5551,
|
||||
DRM_FORMAT_BGRA5551,
|
||||
DRM_FORMAT_RGB565,
|
||||
DRM_FORMAT_BGR565,
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_XBGR8888,
|
||||
DRM_FORMAT_RGBX8888,
|
||||
DRM_FORMAT_BGRX8888,
|
||||
DRM_FORMAT_ARGB8888,
|
||||
DRM_FORMAT_ABGR8888,
|
||||
DRM_FORMAT_RGBA8888,
|
||||
DRM_FORMAT_BGRA8888,
|
||||
DRM_FORMAT_ARGB2101010,
|
||||
DRM_FORMAT_ABGR2101010,
|
||||
DRM_FORMAT_RGBA1010102,
|
||||
DRM_FORMAT_BGRA1010102,
|
||||
/* TODO: non-RGB formats */
|
||||
};
|
||||
|
||||
static const struct vs_formats vs_formats_no_yuv444 = {
|
||||
.array = vs_formats_array_no_yuv444,
|
||||
.num = ARRAY_SIZE(vs_formats_array_no_yuv444)
|
||||
.primary_array = vs_primary_formats_array_no_yuv444,
|
||||
.primary_num = ARRAY_SIZE(vs_primary_formats_array_no_yuv444)
|
||||
};
|
||||
|
||||
static const struct vs_formats vs_formats_with_yuv444 = {
|
||||
.array = vs_formats_array_with_yuv444,
|
||||
.num = ARRAY_SIZE(vs_formats_array_with_yuv444)
|
||||
.primary_array = vs_primary_formats_array_with_yuv444,
|
||||
.primary_num = ARRAY_SIZE(vs_primary_formats_array_with_yuv444)
|
||||
};
|
||||
|
||||
static struct vs_chip_identity vs_chip_identities[] = {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
struct vs_formats {
|
||||
const u32 *array;
|
||||
unsigned int num;
|
||||
const u32 *primary_array;
|
||||
unsigned int primary_num;
|
||||
};
|
||||
|
||||
struct vs_chip_identity {
|
||||
|
|
|
|||
|
|
@ -168,8 +168,8 @@ struct drm_plane *vs_primary_plane_init(struct drm_device *drm_dev, struct vs_dc
|
|||
|
||||
plane = drmm_universal_plane_alloc(drm_dev, struct drm_plane, dev, 0,
|
||||
&vs_primary_plane_funcs,
|
||||
dc->identity.formats->array,
|
||||
dc->identity.formats->num,
|
||||
dc->identity.formats->primary_array,
|
||||
dc->identity.formats->primary_num,
|
||||
NULL,
|
||||
DRM_PLANE_TYPE_PRIMARY,
|
||||
NULL);
|
||||
|
|
|
|||
|
|
@ -318,8 +318,10 @@ void xe_i2c_pm_resume(struct xe_device *xe, bool d3cold)
|
|||
static void xe_i2c_remove(void *data)
|
||||
{
|
||||
struct xe_i2c *i2c = data;
|
||||
struct xe_device *xe = tile_to_xe(i2c->mmio->tile);
|
||||
unsigned int i;
|
||||
|
||||
xe_i2c_irq_reset(xe);
|
||||
xe_amc_exit(i2c);
|
||||
|
||||
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++) {
|
||||
|
|
@ -329,6 +331,7 @@ static void xe_i2c_remove(void *data)
|
|||
|
||||
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
|
||||
xe_i2c_unregister_adapter(i2c);
|
||||
xe->i2c = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#include "xe_mmio_gem.h"
|
||||
|
||||
#include <linux/dma-resv.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_managed.h>
|
||||
|
||||
#include "xe_device_types.h"
|
||||
|
||||
|
|
@ -37,12 +37,24 @@ static vm_fault_t xe_mmio_gem_vm_fault(struct vm_fault *);
|
|||
struct xe_mmio_gem {
|
||||
struct drm_gem_object base;
|
||||
phys_addr_t phys_addr;
|
||||
struct page *dummy_page; /* protected by the GEM's dma_resv */
|
||||
bool destroyed; /* protected by the GEM's dma_resv */
|
||||
};
|
||||
|
||||
static int xe_mmio_gem_vm_may_split(struct vm_area_struct *area, unsigned long addr)
|
||||
{
|
||||
/*
|
||||
* Forbid splitting. Together with VM_DONTEXPAND, this keeps the VMA
|
||||
* matching the GEM object exactly.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct vm_ops = {
|
||||
.open = drm_gem_vm_open,
|
||||
.close = drm_gem_vm_close,
|
||||
.fault = xe_mmio_gem_vm_fault,
|
||||
.may_split = xe_mmio_gem_vm_may_split,
|
||||
};
|
||||
|
||||
static const struct drm_gem_object_funcs xe_mmio_gem_funcs = {
|
||||
|
|
@ -121,6 +133,8 @@ static void xe_mmio_gem_free(struct drm_gem_object *base)
|
|||
{
|
||||
struct xe_mmio_gem *obj = to_xe_mmio_gem(base);
|
||||
|
||||
if (obj->dummy_page)
|
||||
__free_page(obj->dummy_page);
|
||||
drm_gem_object_release(base);
|
||||
kfree(obj);
|
||||
}
|
||||
|
|
@ -128,15 +142,31 @@ static void xe_mmio_gem_free(struct drm_gem_object *base)
|
|||
/**
|
||||
* xe_mmio_gem_destroy - Destroy the GEM object that exposes an MMIO region
|
||||
* @gem: the GEM object to destroy
|
||||
* @file: DRM file descriptor previously passed to xe_mmio_gem_create()
|
||||
*
|
||||
* This function releases resources associated with the GEM object created by
|
||||
* xe_mmio_gem_create().
|
||||
*
|
||||
* See: "Exposing MMIO regions to userspace"
|
||||
*/
|
||||
void xe_mmio_gem_destroy(struct xe_mmio_gem *gem)
|
||||
void xe_mmio_gem_destroy(struct xe_mmio_gem *gem, struct drm_file *file)
|
||||
{
|
||||
xe_mmio_gem_free(&gem->base);
|
||||
struct drm_gem_object *base = &gem->base;
|
||||
struct drm_device *dev = base->dev;
|
||||
|
||||
drm_vma_node_revoke(&base->vma_node, file);
|
||||
|
||||
dma_resv_lock(base->resv, NULL);
|
||||
gem->destroyed = true;
|
||||
dma_resv_unlock(base->resv);
|
||||
/*
|
||||
* Setting 'destroyed' under lock takes care of the subsequent faults.
|
||||
* Zap the existing PTEs to cut off access to the real MMIO through
|
||||
* currently mapped pages.
|
||||
*/
|
||||
drm_vma_node_unmap(&base->vma_node, dev->anon_inode->i_mapping);
|
||||
|
||||
drm_gem_object_put(base);
|
||||
}
|
||||
|
||||
static int xe_mmio_gem_mmap(struct drm_gem_object *base, struct vm_area_struct *vma)
|
||||
|
|
@ -147,8 +177,6 @@ static int xe_mmio_gem_mmap(struct drm_gem_object *base, struct vm_area_struct *
|
|||
if ((vma->vm_flags & VM_SHARED) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Set vm_pgoff (used as a fake buffer offset by DRM) to 0 */
|
||||
vma->vm_pgoff = 0;
|
||||
vma->vm_page_prot = pgprot_noncached(vma_get_page_prot(vma));
|
||||
vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP |
|
||||
VM_DONTCOPY | VM_NORESERVE);
|
||||
|
|
@ -157,51 +185,47 @@ static int xe_mmio_gem_mmap(struct drm_gem_object *base, struct vm_area_struct *
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void xe_mmio_gem_release_dummy_page(struct drm_device *dev, void *res)
|
||||
static int alloc_dummy_page_if_needed(struct drm_gem_object *base)
|
||||
{
|
||||
__free_page((struct page *)res);
|
||||
struct xe_mmio_gem *obj = to_xe_mmio_gem(base);
|
||||
|
||||
dma_resv_assert_held(base->resv);
|
||||
if (!obj->dummy_page)
|
||||
obj->dummy_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
|
||||
return obj->dummy_page ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static vm_fault_t xe_mmio_gem_vm_fault_dummy_page(struct vm_area_struct *vma)
|
||||
static vm_fault_t xe_mmio_gem_vm_fault_dummy_page(struct vm_fault *vmf)
|
||||
{
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
struct drm_gem_object *base = vma->vm_private_data;
|
||||
struct drm_device *dev = base->dev;
|
||||
vm_fault_t ret = VM_FAULT_NOPAGE;
|
||||
struct page *page;
|
||||
struct xe_mmio_gem *obj = to_xe_mmio_gem(base);
|
||||
unsigned long pfn;
|
||||
unsigned long i;
|
||||
|
||||
page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (!page)
|
||||
if (alloc_dummy_page_if_needed(base))
|
||||
return VM_FAULT_OOM;
|
||||
|
||||
if (drmm_add_action_or_reset(dev, xe_mmio_gem_release_dummy_page, page))
|
||||
return VM_FAULT_OOM;
|
||||
pfn = page_to_pfn(obj->dummy_page);
|
||||
|
||||
pfn = page_to_pfn(page);
|
||||
|
||||
/* Map the entire VMA to the same dummy page */
|
||||
for (i = 0; i < base->size; i += PAGE_SIZE) {
|
||||
unsigned long addr = vma->vm_start + i;
|
||||
|
||||
ret = vmf_insert_pfn(vma, addr, pfn);
|
||||
if (ret & VM_FAULT_ERROR)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return vmf_insert_pfn_prot(vma, vmf->address, pfn,
|
||||
vm_get_page_prot(vma->vm_flags));
|
||||
}
|
||||
|
||||
static vm_fault_t xe_mmio_gem_vm_fault(struct vm_fault *vmf)
|
||||
static vm_fault_t xe_mmio_gem_vm_fault_locked(struct vm_fault *vmf)
|
||||
{
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
struct drm_gem_object *base = vma->vm_private_data;
|
||||
struct xe_mmio_gem *obj = to_xe_mmio_gem(base);
|
||||
struct drm_device *dev = base->dev;
|
||||
vm_fault_t ret = VM_FAULT_NOPAGE;
|
||||
unsigned long i;
|
||||
unsigned long addr, pfn;
|
||||
int idx;
|
||||
|
||||
dma_resv_assert_held(base->resv);
|
||||
if (obj->destroyed)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (!drm_dev_enter(dev, &idx)) {
|
||||
/*
|
||||
* Provide a dummy page to avoid SIGBUS for events such as hot-unplug.
|
||||
|
|
@ -209,18 +233,30 @@ static vm_fault_t xe_mmio_gem_vm_fault(struct vm_fault *vmf)
|
|||
* It is assumed the userspace will receive the notification via some
|
||||
* other channel (e.g. drm uevent).
|
||||
*/
|
||||
return xe_mmio_gem_vm_fault_dummy_page(vma);
|
||||
return xe_mmio_gem_vm_fault_dummy_page(vmf);
|
||||
}
|
||||
|
||||
for (i = 0; i < base->size; i += PAGE_SIZE) {
|
||||
unsigned long addr = vma->vm_start + i;
|
||||
unsigned long phys_addr = obj->phys_addr + i;
|
||||
|
||||
ret = vmf_insert_pfn(vma, addr, PHYS_PFN(phys_addr));
|
||||
pfn = PHYS_PFN(obj->phys_addr);
|
||||
for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
|
||||
ret = vmf_insert_pfn(vma, addr, pfn);
|
||||
if (ret & VM_FAULT_ERROR)
|
||||
break;
|
||||
|
||||
pfn++;
|
||||
}
|
||||
|
||||
drm_dev_exit(idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static vm_fault_t xe_mmio_gem_vm_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
struct drm_gem_object *base = vma->vm_private_data;
|
||||
vm_fault_t ret;
|
||||
|
||||
dma_resv_lock(base->resv, NULL);
|
||||
ret = xe_mmio_gem_vm_fault_locked(vmf);
|
||||
dma_resv_unlock(base->resv);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ struct xe_mmio_gem;
|
|||
struct xe_mmio_gem *xe_mmio_gem_create(struct xe_device *xe, struct drm_file *file,
|
||||
phys_addr_t phys_addr, size_t size);
|
||||
u64 xe_mmio_gem_mmap_offset(struct xe_mmio_gem *gem);
|
||||
void xe_mmio_gem_destroy(struct xe_mmio_gem *gem);
|
||||
void xe_mmio_gem_destroy(struct xe_mmio_gem *gem, struct drm_file *file);
|
||||
|
||||
#endif /* _XE_MMIO_GEM_H_ */
|
||||
|
|
|
|||
|
|
@ -54,13 +54,40 @@ xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgea
|
|||
write_unlock(&shrinker->lock);
|
||||
}
|
||||
|
||||
static s64 __xe_shrinker_walk(struct xe_device *xe,
|
||||
static bool __xe_shrinker_runtime_pm_get(struct xe_shrinker *shrinker)
|
||||
{
|
||||
struct xe_device *xe = shrinker->xe;
|
||||
|
||||
if (xe_pm_runtime_get_if_active(xe))
|
||||
return true;
|
||||
|
||||
if (xe_rpm_reclaim_safe(xe) && !ttm_bo_shrink_avoid_wait()) {
|
||||
xe_pm_runtime_get(xe);
|
||||
return true;
|
||||
}
|
||||
|
||||
queue_work(xe->unordered_wq, &shrinker->pm_worker);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void xe_shrinker_runtime_pm_put(struct xe_shrinker *shrinker, bool runtime_pm)
|
||||
{
|
||||
if (runtime_pm)
|
||||
xe_pm_runtime_put(shrinker->xe);
|
||||
}
|
||||
|
||||
static int __xe_shrinker_walk(struct xe_shrinker *shrinker,
|
||||
struct ttm_operation_ctx *ctx,
|
||||
const struct xe_bo_shrink_flags flags,
|
||||
unsigned long to_scan, unsigned long *scanned)
|
||||
unsigned long to_scan, unsigned long *scanned,
|
||||
unsigned long *freed)
|
||||
{
|
||||
struct xe_device *xe = shrinker->xe;
|
||||
unsigned int mem_type;
|
||||
s64 freed = 0, lret;
|
||||
bool rpm = false;
|
||||
int ret = 0;
|
||||
s64 lret;
|
||||
|
||||
for (mem_type = XE_PL_SYSTEM; mem_type <= XE_PL_TT; ++mem_type) {
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&xe->ttm, mem_type);
|
||||
|
|
@ -74,23 +101,35 @@ static s64 __xe_shrinker_walk(struct xe_device *xe,
|
|||
if (!man || !man->use_tt)
|
||||
continue;
|
||||
|
||||
if (mem_type != XE_PL_SYSTEM && !rpm &&
|
||||
xe_device_is_l2_flush_optimized(xe)) {
|
||||
if (!__xe_shrinker_runtime_pm_get(shrinker))
|
||||
break;
|
||||
rpm = true;
|
||||
}
|
||||
|
||||
ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) {
|
||||
if (!ttm_bo_shrink_suitable(ttm_bo, ctx))
|
||||
continue;
|
||||
|
||||
lret = xe_bo_shrink(ctx, ttm_bo, flags, scanned);
|
||||
if (lret < 0)
|
||||
return lret;
|
||||
if (lret < 0) {
|
||||
ret = lret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
freed += lret;
|
||||
*freed += lret;
|
||||
if (*scanned >= to_scan)
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
/* Trylocks should never error, just fail. */
|
||||
xe_assert(xe, !IS_ERR(ttm_bo));
|
||||
}
|
||||
|
||||
return freed;
|
||||
out:
|
||||
xe_shrinker_runtime_pm_put(shrinker, rpm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -99,40 +138,36 @@ static s64 __xe_shrinker_walk(struct xe_device *xe,
|
|||
* add writeback. This avoids stalls and explicit writebacks with light or
|
||||
* moderate memory pressure.
|
||||
*/
|
||||
static s64 xe_shrinker_walk(struct xe_device *xe,
|
||||
static int xe_shrinker_walk(struct xe_shrinker *shrinker,
|
||||
struct ttm_operation_ctx *ctx,
|
||||
const struct xe_bo_shrink_flags flags,
|
||||
unsigned long to_scan, unsigned long *scanned)
|
||||
unsigned long to_scan, unsigned long *scanned,
|
||||
unsigned long *freed)
|
||||
{
|
||||
bool no_wait_gpu = true;
|
||||
struct xe_bo_shrink_flags save_flags = flags;
|
||||
s64 lret, freed;
|
||||
int ret;
|
||||
|
||||
swap(no_wait_gpu, ctx->no_wait_gpu);
|
||||
save_flags.writeback = false;
|
||||
lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned);
|
||||
ret = __xe_shrinker_walk(shrinker, ctx, save_flags, to_scan, scanned,
|
||||
freed);
|
||||
swap(no_wait_gpu, ctx->no_wait_gpu);
|
||||
if (lret < 0 || *scanned >= to_scan)
|
||||
return lret;
|
||||
if (ret || *scanned >= to_scan)
|
||||
return ret;
|
||||
|
||||
freed = lret;
|
||||
if (!ctx->no_wait_gpu) {
|
||||
lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned);
|
||||
if (lret < 0)
|
||||
return lret;
|
||||
freed += lret;
|
||||
if (*scanned >= to_scan)
|
||||
return freed;
|
||||
ret = __xe_shrinker_walk(shrinker, ctx, save_flags, to_scan, scanned,
|
||||
freed);
|
||||
if (ret || *scanned >= to_scan)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (flags.writeback) {
|
||||
lret = __xe_shrinker_walk(xe, ctx, flags, to_scan, scanned);
|
||||
if (lret < 0)
|
||||
return lret;
|
||||
freed += lret;
|
||||
}
|
||||
if (flags.writeback)
|
||||
ret = __xe_shrinker_walk(shrinker, ctx, flags, to_scan, scanned,
|
||||
freed);
|
||||
|
||||
return freed;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
|
|
@ -180,22 +215,7 @@ static bool xe_shrinker_runtime_pm_get(struct xe_shrinker *shrinker, bool force,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!xe_pm_runtime_get_if_active(xe)) {
|
||||
if (xe_rpm_reclaim_safe(xe) && !ttm_bo_shrink_avoid_wait()) {
|
||||
xe_pm_runtime_get(xe);
|
||||
return true;
|
||||
}
|
||||
queue_work(xe->unordered_wq, &shrinker->pm_worker);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void xe_shrinker_runtime_pm_put(struct xe_shrinker *shrinker, bool runtime_pm)
|
||||
{
|
||||
if (runtime_pm)
|
||||
xe_pm_runtime_put(shrinker->xe);
|
||||
return __xe_shrinker_runtime_pm_get(shrinker);
|
||||
}
|
||||
|
||||
static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
|
||||
|
|
@ -214,7 +234,6 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con
|
|||
bool runtime_pm;
|
||||
bool purgeable;
|
||||
bool can_backup = !!(sc->gfp_mask & __GFP_FS);
|
||||
s64 lret;
|
||||
|
||||
nr_to_scan = sc->nr_to_scan;
|
||||
|
||||
|
|
@ -225,12 +244,9 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con
|
|||
/* Might need runtime PM. Try to wake early if it looks like it. */
|
||||
runtime_pm = xe_shrinker_runtime_pm_get(shrinker, false, nr_to_scan, can_backup);
|
||||
|
||||
if (purgeable && nr_scanned < nr_to_scan) {
|
||||
lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags,
|
||||
nr_to_scan, &nr_scanned);
|
||||
if (lret >= 0)
|
||||
freed += lret;
|
||||
}
|
||||
if (purgeable && nr_scanned < nr_to_scan)
|
||||
xe_shrinker_walk(shrinker, &ctx, shrink_flags,
|
||||
nr_to_scan, &nr_scanned, &freed);
|
||||
|
||||
sc->nr_scanned = nr_scanned;
|
||||
if (nr_scanned >= nr_to_scan || !can_backup)
|
||||
|
|
@ -242,10 +258,8 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con
|
|||
|
||||
shrink_flags.purge = false;
|
||||
|
||||
lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags,
|
||||
nr_to_scan, &nr_scanned);
|
||||
if (lret >= 0)
|
||||
freed += lret;
|
||||
xe_shrinker_walk(shrinker, &ctx, shrink_flags,
|
||||
nr_to_scan, &nr_scanned, &freed);
|
||||
|
||||
sc->nr_scanned = nr_scanned;
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ struct dma_fence_ops {
|
|||
* compute the name at runtime, without having it to store permanently
|
||||
* for each fence, or build a cache of some sort.
|
||||
*
|
||||
* The returned string is RCU protected and can be freed after the fence
|
||||
* signaled and a RCU grace period passed.
|
||||
*
|
||||
* This callback is mandatory.
|
||||
*/
|
||||
const char * (*get_driver_name)(struct dma_fence *fence);
|
||||
|
|
@ -153,6 +156,9 @@ struct dma_fence_ops {
|
|||
* having it to store permanently for each fence, or build a cache of
|
||||
* some sort.
|
||||
*
|
||||
* The returned string is RCU protected and can be freed after the fence
|
||||
* signaled and a RCU grace period passed.
|
||||
*
|
||||
* This callback is mandatory.
|
||||
*/
|
||||
const char * (*get_timeline_name)(struct dma_fence *fence);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user