Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'drm-fixes-2024-12-07' of https://gitlab.freedesktop.org/drm/kernel

Pull drm fixes from Dave Airlie:
"Pretty quiet week which is probably expected after US holidays, the
dma-fence and displayport MST message handling fixes make up the bulk
of this, along with a couple of minor xe and other driver fixes.

dma-fence:
- Fix reference leak on fence-merge failure path
- Simplify fence merging with kernel's sort()
- Fix dma_fence_array_signaled() to ensure forward progress

dp_mst:
- Fix MST sideband message body length check
- Fix a bunch of locking/state handling with DP MST msgs

sti:
- Add __iomem for mixer_dbg_mxn()'s parameter

xe:
- Missing init value and 64-bit write-order check
- Fix a memory allocation issue causing lockdep violation

v3d:
- Performance counter fix"

* tag 'drm-fixes-2024-12-07' of https://gitlab.freedesktop.org/drm/kernel:
drm/v3d: Enable Performance Counters before clearing them
drm/dp_mst: Use reset_msg_rx_state() instead of open coding it
drm/dp_mst: Reset message rx state after OOM in drm_dp_mst_handle_up_req()
drm/dp_mst: Ensure mst_primary pointer is valid in drm_dp_mst_handle_up_req()
drm/dp_mst: Fix down request message timeout handling
drm/dp_mst: Simplify error path in drm_dp_mst_handle_down_rep()
drm/dp_mst: Verify request type in the corresponding down message reply
drm/dp_mst: Fix resetting msg rx state after topology removal
drm/xe: Move the coredump registration to the worker thread
drm/xe/guc: Fix missing init value and add register order check
drm/sti: Add __iomem for mixer_dbg_mxn's parameter
drm/dp_mst: Fix MST sideband message body length check
dma-buf: fix dma_fence_array_signaled v4
dma-fence: Use kernel's sort for merging fences
dma-fence: Fix reference leak on fence merge failure path

+285 -137
+27 -1
drivers/dma-buf/dma-fence-array.c
··· 103 103 static bool dma_fence_array_signaled(struct dma_fence *fence) 104 104 { 105 105 struct dma_fence_array *array = to_dma_fence_array(fence); 106 + int num_pending; 107 + unsigned int i; 106 108 107 - if (atomic_read(&array->num_pending) > 0) 109 + /* 110 + * We need to read num_pending before checking the enable_signal bit 111 + * to avoid racing with the enable_signaling() implementation, which 112 + * might decrement the counter, and cause a partial check. 113 + * atomic_read_acquire() pairs with atomic_dec_and_test() in 114 + * dma_fence_array_enable_signaling() 115 + * 116 + * The !--num_pending check is here to account for the any_signaled case 117 + * if we race with enable_signaling(), that means the !num_pending check 118 + * in the is_signalling_enabled branch might be outdated (num_pending 119 + * might have been decremented), but that's fine. The user will get the 120 + * right value when testing again later. 121 + */ 122 + num_pending = atomic_read_acquire(&array->num_pending); 123 + if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &array->base.flags)) { 124 + if (num_pending <= 0) 125 + goto signal; 108 126 return false; 127 + } 109 128 129 + for (i = 0; i < array->num_fences; ++i) { 130 + if (dma_fence_is_signaled(array->fences[i]) && !--num_pending) 131 + goto signal; 132 + } 133 + return false; 134 + 135 + signal: 110 136 dma_fence_array_clear_pending_error(array); 111 137 return true; 112 138 }
+61 -65
drivers/dma-buf/dma-fence-unwrap.c
··· 12 12 #include <linux/dma-fence-chain.h> 13 13 #include <linux/dma-fence-unwrap.h> 14 14 #include <linux/slab.h> 15 + #include <linux/sort.h> 15 16 16 17 /* Internal helper to start new array iteration, don't use directly */ 17 18 static struct dma_fence * ··· 60 59 } 61 60 EXPORT_SYMBOL_GPL(dma_fence_unwrap_next); 62 61 62 + 63 + static int fence_cmp(const void *_a, const void *_b) 64 + { 65 + struct dma_fence *a = *(struct dma_fence **)_a; 66 + struct dma_fence *b = *(struct dma_fence **)_b; 67 + 68 + if (a->context < b->context) 69 + return -1; 70 + else if (a->context > b->context) 71 + return 1; 72 + 73 + if (dma_fence_is_later(b, a)) 74 + return 1; 75 + else if (dma_fence_is_later(a, b)) 76 + return -1; 77 + 78 + return 0; 79 + } 80 + 63 81 /* Implementation for the dma_fence_merge() marco, don't use directly */ 64 82 struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, 65 83 struct dma_fence **fences, ··· 87 67 struct dma_fence_array *result; 88 68 struct dma_fence *tmp, **array; 89 69 ktime_t timestamp; 90 - unsigned int i; 91 - size_t count; 70 + int i, j, count; 92 71 93 72 count = 0; 94 73 timestamp = ns_to_ktime(0); ··· 115 96 if (!array) 116 97 return NULL; 117 98 118 - /* 119 - * This trashes the input fence array and uses it as position for the 120 - * following merge loop. This works because the dma_fence_merge() 121 - * wrapper macro is creating this temporary array on the stack together 122 - * with the iterators. 123 - */ 124 - for (i = 0; i < num_fences; ++i) 125 - fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]); 126 - 127 99 count = 0; 128 - do { 129 - unsigned int sel; 130 - 131 - restart: 132 - tmp = NULL; 133 - for (i = 0; i < num_fences; ++i) { 134 - struct dma_fence *next; 135 - 136 - while (fences[i] && dma_fence_is_signaled(fences[i])) 137 - fences[i] = dma_fence_unwrap_next(&iter[i]); 138 - 139 - next = fences[i]; 140 - if (!next) 141 - continue; 142 - 143 - /* 144 - * We can't guarantee that inpute fences are ordered by 145 - * context, but it is still quite likely when this 146 - * function is used multiple times. So attempt to order 147 - * the fences by context as we pass over them and merge 148 - * fences with the same context. 149 - */ 150 - if (!tmp || tmp->context > next->context) { 151 - tmp = next; 152 - sel = i; 153 - 154 - } else if (tmp->context < next->context) { 155 - continue; 156 - 157 - } else if (dma_fence_is_later(tmp, next)) { 158 - fences[i] = dma_fence_unwrap_next(&iter[i]); 159 - goto restart; 100 + for (i = 0; i < num_fences; ++i) { 101 + dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) { 102 + if (!dma_fence_is_signaled(tmp)) { 103 + array[count++] = dma_fence_get(tmp); 160 104 } else { 161 - fences[sel] = dma_fence_unwrap_next(&iter[sel]); 162 - goto restart; 105 + ktime_t t = dma_fence_timestamp(tmp); 106 + 107 + if (ktime_after(t, timestamp)) 108 + timestamp = t; 163 109 } 164 110 } 111 + } 165 112 166 - if (tmp) { 167 - array[count++] = dma_fence_get(tmp); 168 - fences[sel] = dma_fence_unwrap_next(&iter[sel]); 113 + if (count == 0 || count == 1) 114 + goto return_fastpath; 115 + 116 + sort(array, count, sizeof(*array), fence_cmp, NULL); 117 + 118 + /* 119 + * Only keep the most recent fence for each context. 120 + */ 121 + j = 0; 122 + for (i = 1; i < count; i++) { 123 + if (array[i]->context == array[j]->context) 124 + dma_fence_put(array[i]); 125 + else 126 + array[++j] = array[i]; 127 + } 128 + count = ++j; 129 + 130 + if (count > 1) { 131 + result = dma_fence_array_create(count, array, 132 + dma_fence_context_alloc(1), 133 + 1, false); 134 + if (!result) { 135 + for (i = 0; i < count; i++) 136 + dma_fence_put(array[i]); 137 + tmp = NULL; 138 + goto return_tmp; 169 139 } 170 - } while (tmp); 171 - 172 - if (count == 0) { 173 - tmp = dma_fence_allocate_private_stub(ktime_get()); 174 - goto return_tmp; 140 + return &result->base; 175 141 } 176 142 177 - if (count == 1) { 143 + return_fastpath: 144 + if (count == 0) 145 + tmp = dma_fence_allocate_private_stub(timestamp); 146 + else 178 147 tmp = array[0]; 179 - goto return_tmp; 180 - } 181 - 182 - result = dma_fence_array_create(count, array, 183 - dma_fence_context_alloc(1), 184 - 1, false); 185 - if (!result) { 186 - tmp = NULL; 187 - goto return_tmp; 188 - } 189 - return &result->base; 190 148 191 149 return_tmp: 192 150 kfree(array);
+87 -20
drivers/gpu/drm/display/drm_dp_mst_topology.c
··· 320 320 hdr->broadcast = (buf[idx] >> 7) & 0x1; 321 321 hdr->path_msg = (buf[idx] >> 6) & 0x1; 322 322 hdr->msg_len = buf[idx] & 0x3f; 323 + if (hdr->msg_len < 1) /* min space for body CRC */ 324 + return false; 325 + 323 326 idx++; 324 327 hdr->somt = (buf[idx] >> 7) & 0x1; 325 328 hdr->eomt = (buf[idx] >> 6) & 0x1; ··· 3700 3697 ret = 0; 3701 3698 mgr->payload_id_table_cleared = false; 3702 3699 3703 - memset(&mgr->down_rep_recv, 0, sizeof(mgr->down_rep_recv)); 3704 - memset(&mgr->up_req_recv, 0, sizeof(mgr->up_req_recv)); 3700 + mgr->reset_rx_state = true; 3705 3701 } 3706 3702 3707 3703 out_unlock: ··· 3858 3856 } 3859 3857 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume); 3860 3858 3859 + static void reset_msg_rx_state(struct drm_dp_sideband_msg_rx *msg) 3860 + { 3861 + memset(msg, 0, sizeof(*msg)); 3862 + } 3863 + 3861 3864 static bool 3862 3865 drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up, 3863 3866 struct drm_dp_mst_branch **mstb) ··· 3941 3934 return true; 3942 3935 } 3943 3936 3937 + static int get_msg_request_type(u8 data) 3938 + { 3939 + return data & 0x7f; 3940 + } 3941 + 3942 + static bool verify_rx_request_type(struct drm_dp_mst_topology_mgr *mgr, 3943 + const struct drm_dp_sideband_msg_tx *txmsg, 3944 + const struct drm_dp_sideband_msg_rx *rxmsg) 3945 + { 3946 + const struct drm_dp_sideband_msg_hdr *hdr = &rxmsg->initial_hdr; 3947 + const struct drm_dp_mst_branch *mstb = txmsg->dst; 3948 + int tx_req_type = get_msg_request_type(txmsg->msg[0]); 3949 + int rx_req_type = get_msg_request_type(rxmsg->msg[0]); 3950 + char rad_str[64]; 3951 + 3952 + if (tx_req_type == rx_req_type) 3953 + return true; 3954 + 3955 + drm_dp_mst_rad_to_str(mstb->rad, mstb->lct, rad_str, sizeof(rad_str)); 3956 + drm_dbg_kms(mgr->dev, 3957 + "Got unexpected MST reply, mstb: %p seqno: %d lct: %d rad: %s rx_req_type: %s (%02x) != tx_req_type: %s (%02x)\n", 3958 + mstb, hdr->seqno, mstb->lct, rad_str, 3959 + drm_dp_mst_req_type_str(rx_req_type), rx_req_type, 3960 + drm_dp_mst_req_type_str(tx_req_type), tx_req_type); 3961 + 3962 + return false; 3963 + } 3964 + 3944 3965 static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr) 3945 3966 { 3946 3967 struct drm_dp_sideband_msg_tx *txmsg; ··· 3984 3949 3985 3950 /* find the message */ 3986 3951 mutex_lock(&mgr->qlock); 3952 + 3987 3953 txmsg = list_first_entry_or_null(&mgr->tx_msg_downq, 3988 3954 struct drm_dp_sideband_msg_tx, next); 3989 - mutex_unlock(&mgr->qlock); 3990 3955 3991 3956 /* Were we actually expecting a response, and from this mstb? */ 3992 3957 if (!txmsg || txmsg->dst != mstb) { ··· 3995 3960 hdr = &msg->initial_hdr; 3996 3961 drm_dbg_kms(mgr->dev, "Got MST reply with no msg %p %d %d %02x %02x\n", 3997 3962 mstb, hdr->seqno, hdr->lct, hdr->rad[0], msg->msg[0]); 3963 + 3964 + mutex_unlock(&mgr->qlock); 3965 + 3966 + goto out_clear_reply; 3967 + } 3968 + 3969 + if (!verify_rx_request_type(mgr, txmsg, msg)) { 3970 + mutex_unlock(&mgr->qlock); 3971 + 3998 3972 goto out_clear_reply; 3999 3973 } 4000 3974 ··· 4019 3975 txmsg->reply.u.nak.nak_data); 4020 3976 } 4021 3977 4022 - memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx)); 4023 - drm_dp_mst_topology_put_mstb(mstb); 4024 - 4025 - mutex_lock(&mgr->qlock); 4026 3978 txmsg->state = DRM_DP_SIDEBAND_TX_RX; 4027 3979 list_del(&txmsg->next); 3980 + 4028 3981 mutex_unlock(&mgr->qlock); 4029 3982 4030 3983 wake_up_all(&mgr->tx_waitq); 4031 3984 4032 - return 0; 4033 - 4034 3985 out_clear_reply: 4035 - memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx)); 3986 + reset_msg_rx_state(msg); 4036 3987 out: 4037 3988 if (mstb) 4038 3989 drm_dp_mst_topology_put_mstb(mstb); ··· 4109 4070 static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) 4110 4071 { 4111 4072 struct drm_dp_pending_up_req *up_req; 4073 + struct drm_dp_mst_branch *mst_primary; 4074 + int ret = 0; 4112 4075 4113 4076 if (!drm_dp_get_one_sb_msg(mgr, true, NULL)) 4114 - goto out; 4077 + goto out_clear_reply; 4115 4078 4116 4079 if (!mgr->up_req_recv.have_eomt) 4117 4080 return 0; 4118 4081 4119 4082 up_req = kzalloc(sizeof(*up_req), GFP_KERNEL); 4120 - if (!up_req) 4121 - return -ENOMEM; 4083 + if (!up_req) { 4084 + ret = -ENOMEM; 4085 + goto out_clear_reply; 4086 + } 4122 4087 4123 4088 INIT_LIST_HEAD(&up_req->next); 4124 4089 ··· 4133 4090 drm_dbg_kms(mgr->dev, "Received unknown up req type, ignoring: %x\n", 4134 4091 up_req->msg.req_type); 4135 4092 kfree(up_req); 4136 - goto out; 4093 + goto out_clear_reply; 4137 4094 } 4138 4095 4139 - drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, up_req->msg.req_type, 4096 + mutex_lock(&mgr->lock); 4097 + mst_primary = mgr->mst_primary; 4098 + if (!mst_primary || !drm_dp_mst_topology_try_get_mstb(mst_primary)) { 4099 + mutex_unlock(&mgr->lock); 4100 + kfree(up_req); 4101 + goto out_clear_reply; 4102 + } 4103 + mutex_unlock(&mgr->lock); 4104 + 4105 + drm_dp_send_up_ack_reply(mgr, mst_primary, up_req->msg.req_type, 4140 4106 false); 4141 4107 4142 4108 if (up_req->msg.req_type == DP_CONNECTION_STATUS_NOTIFY) { ··· 4162 4110 conn_stat->peer_device_type); 4163 4111 4164 4112 mutex_lock(&mgr->probe_lock); 4165 - handle_csn = mgr->mst_primary->link_address_sent; 4113 + handle_csn = mst_primary->link_address_sent; 4166 4114 mutex_unlock(&mgr->probe_lock); 4167 4115 4168 4116 if (!handle_csn) { 4169 4117 drm_dbg_kms(mgr->dev, "Got CSN before finish topology probing. Skip it."); 4170 4118 kfree(up_req); 4171 - goto out; 4119 + goto out_put_primary; 4172 4120 } 4173 4121 } else if (up_req->msg.req_type == DP_RESOURCE_STATUS_NOTIFY) { 4174 4122 const struct drm_dp_resource_status_notify *res_stat = ··· 4185 4133 mutex_unlock(&mgr->up_req_lock); 4186 4134 queue_work(system_long_wq, &mgr->up_req_work); 4187 4135 4188 - out: 4189 - memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); 4190 - return 0; 4136 + out_put_primary: 4137 + drm_dp_mst_topology_put_mstb(mst_primary); 4138 + out_clear_reply: 4139 + reset_msg_rx_state(&mgr->up_req_recv); 4140 + return ret; 4141 + } 4142 + 4143 + static void update_msg_rx_state(struct drm_dp_mst_topology_mgr *mgr) 4144 + { 4145 + mutex_lock(&mgr->lock); 4146 + if (mgr->reset_rx_state) { 4147 + mgr->reset_rx_state = false; 4148 + reset_msg_rx_state(&mgr->down_rep_recv); 4149 + reset_msg_rx_state(&mgr->up_req_recv); 4150 + } 4151 + mutex_unlock(&mgr->lock); 4191 4152 } 4192 4153 4193 4154 /** ··· 4236 4171 mgr->sink_count = sc; 4237 4172 *handled = true; 4238 4173 } 4174 + 4175 + update_msg_rx_state(mgr); 4239 4176 4240 4177 if (esi[1] & DP_DOWN_REP_MSG_RDY) { 4241 4178 ret = drm_dp_mst_handle_down_rep(mgr);
+1 -1
drivers/gpu/drm/sti/sti_mixer.c
··· 137 137 } 138 138 } 139 139 140 - static void mixer_dbg_mxn(struct seq_file *s, void *addr) 140 + static void mixer_dbg_mxn(struct seq_file *s, void __iomem *addr) 141 141 { 142 142 int i; 143 143
+1 -1
drivers/gpu/drm/v3d/v3d_perfmon.c
··· 254 254 V3D_CORE_WRITE(0, V3D_V4_PCTR_0_SRC_X(source), channel); 255 255 } 256 256 257 + V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, mask); 257 258 V3D_CORE_WRITE(0, V3D_V4_PCTR_0_CLR, mask); 258 259 V3D_CORE_WRITE(0, V3D_PCTR_0_OVERFLOW, mask); 259 - V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, mask); 260 260 261 261 v3d->active_perfmon = perfmon; 262 262 }
+39 -34
drivers/gpu/drm/xe/xe_devcoredump.c
··· 155 155 ss->vm = NULL; 156 156 } 157 157 158 - static void xe_devcoredump_deferred_snap_work(struct work_struct *work) 159 - { 160 - struct xe_devcoredump_snapshot *ss = container_of(work, typeof(*ss), work); 161 - struct xe_devcoredump *coredump = container_of(ss, typeof(*coredump), snapshot); 162 - struct xe_device *xe = coredump_to_xe(coredump); 163 - unsigned int fw_ref; 164 - 165 - xe_pm_runtime_get(xe); 166 - 167 - /* keep going if fw fails as we still want to save the memory and SW data */ 168 - fw_ref = xe_force_wake_get(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL); 169 - if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) 170 - xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n"); 171 - xe_vm_snapshot_capture_delayed(ss->vm); 172 - xe_guc_exec_queue_snapshot_capture_delayed(ss->ge); 173 - xe_force_wake_put(gt_to_fw(ss->gt), fw_ref); 174 - 175 - xe_pm_runtime_put(xe); 176 - 177 - /* Calculate devcoredump size */ 178 - ss->read.size = __xe_devcoredump_read(NULL, INT_MAX, coredump); 179 - 180 - ss->read.buffer = kvmalloc(ss->read.size, GFP_USER); 181 - if (!ss->read.buffer) 182 - return; 183 - 184 - __xe_devcoredump_read(ss->read.buffer, ss->read.size, coredump); 185 - xe_devcoredump_snapshot_free(ss); 186 - } 187 - 188 158 static ssize_t xe_devcoredump_read(char *buffer, loff_t offset, 189 159 size_t count, void *data, size_t datalen) 190 160 { ··· 202 232 coredump->job = NULL; 203 233 drm_info(&coredump_to_xe(coredump)->drm, 204 234 "Xe device coredump has been deleted.\n"); 235 + } 236 + 237 + static void xe_devcoredump_deferred_snap_work(struct work_struct *work) 238 + { 239 + struct xe_devcoredump_snapshot *ss = container_of(work, typeof(*ss), work); 240 + struct xe_devcoredump *coredump = container_of(ss, typeof(*coredump), snapshot); 241 + struct xe_device *xe = coredump_to_xe(coredump); 242 + unsigned int fw_ref; 243 + 244 + /* 245 + * NB: Despite passing a GFP_ flags parameter here, more allocations are done 246 + * internally using GFP_KERNEL expliictly. Hence this call must be in the worker 247 + * thread and not in the initial capture call. 248 + */ 249 + dev_coredumpm_timeout(gt_to_xe(ss->gt)->drm.dev, THIS_MODULE, coredump, 0, GFP_KERNEL, 250 + xe_devcoredump_read, xe_devcoredump_free, 251 + XE_COREDUMP_TIMEOUT_JIFFIES); 252 + 253 + xe_pm_runtime_get(xe); 254 + 255 + /* keep going if fw fails as we still want to save the memory and SW data */ 256 + fw_ref = xe_force_wake_get(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL); 257 + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) 258 + xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n"); 259 + xe_vm_snapshot_capture_delayed(ss->vm); 260 + xe_guc_exec_queue_snapshot_capture_delayed(ss->ge); 261 + xe_force_wake_put(gt_to_fw(ss->gt), fw_ref); 262 + 263 + xe_pm_runtime_put(xe); 264 + 265 + /* Calculate devcoredump size */ 266 + ss->read.size = __xe_devcoredump_read(NULL, INT_MAX, coredump); 267 + 268 + ss->read.buffer = kvmalloc(ss->read.size, GFP_USER); 269 + if (!ss->read.buffer) 270 + return; 271 + 272 + __xe_devcoredump_read(ss->read.buffer, ss->read.size, coredump); 273 + xe_devcoredump_snapshot_free(ss); 205 274 } 206 275 207 276 static void devcoredump_snapshot(struct xe_devcoredump *coredump, ··· 319 310 drm_info(&xe->drm, "Xe device coredump has been created\n"); 320 311 drm_info(&xe->drm, "Check your /sys/class/drm/card%d/device/devcoredump/data\n", 321 312 xe->drm.primary->index); 322 - 323 - dev_coredumpm_timeout(xe->drm.dev, THIS_MODULE, coredump, 0, GFP_KERNEL, 324 - xe_devcoredump_read, xe_devcoredump_free, 325 - XE_COREDUMP_TIMEOUT_JIFFIES); 326 313 } 327 314 328 315 static void xe_driver_devcoredump_fini(void *arg)
+62 -15
drivers/gpu/drm/xe/xe_guc_capture.c
··· 102 102 * A 64 bit register define requires 2 consecutive entries, 103 103 * with low dword first and hi dword the second. 104 104 * 2. Register name: null for incompleted define 105 + * 3. Incorrect order will trigger XE_WARN. 105 106 */ 106 107 #define COMMON_XELP_BASE_GLOBAL \ 107 108 { FORCEWAKE_GT, REG_32BIT, 0, 0, "FORCEWAKE_GT"} ··· 1676 1675 struct xe_devcoredump *devcoredump = &xe->devcoredump; 1677 1676 struct xe_devcoredump_snapshot *devcore_snapshot = &devcoredump->snapshot; 1678 1677 struct gcap_reg_list_info *reginfo = NULL; 1679 - u32 last_value, i; 1680 - bool is_ext; 1678 + u32 i, last_value = 0; 1679 + bool is_ext, low32_ready = false; 1681 1680 1682 - if (!list || list->num_regs == 0) 1681 + if (!list || !list->list || list->num_regs == 0) 1683 1682 return; 1684 1683 XE_WARN_ON(!devcore_snapshot->matched_node); 1685 1684 ··· 1702 1701 continue; 1703 1702 1704 1703 value = reg->value; 1705 - if (reg_desc->data_type == REG_64BIT_LOW_DW) { 1704 + switch (reg_desc->data_type) { 1705 + case REG_64BIT_LOW_DW: 1706 1706 last_value = value; 1707 + 1708 + /* 1709 + * A 64 bit register define requires 2 consecutive 1710 + * entries in register list, with low dword first 1711 + * and hi dword the second, like: 1712 + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, 1713 + * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, "XXX_REG"}, 1714 + * 1715 + * Incorrect order will trigger XE_WARN. 1716 + * 1717 + * Possible double low here, for example: 1718 + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, 1719 + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, 1720 + */ 1721 + XE_WARN_ON(low32_ready); 1722 + low32_ready = true; 1707 1723 /* Low 32 bit dword saved, continue for high 32 bit */ 1708 - continue; 1709 - } else if (reg_desc->data_type == REG_64BIT_HI_DW) { 1724 + break; 1725 + 1726 + case REG_64BIT_HI_DW: { 1710 1727 u64 value_qw = ((u64)value << 32) | last_value; 1711 1728 1729 + /* 1730 + * Incorrect 64bit register order. Possible missing low. 1731 + * for example: 1732 + * { XXX_REG(0), REG_32BIT, 0, 0, NULL}, 1733 + * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, NULL}, 1734 + */ 1735 + XE_WARN_ON(!low32_ready); 1736 + low32_ready = false; 1737 + 1712 1738 drm_printf(p, "\t%s: 0x%016llx\n", reg_desc->regname, value_qw); 1713 - continue; 1739 + break; 1714 1740 } 1715 1741 1716 - if (is_ext) { 1717 - int dss, group, instance; 1742 + case REG_32BIT: 1743 + /* 1744 + * Incorrect 64bit register order. Possible missing high. 1745 + * for example: 1746 + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, 1747 + * { XXX_REG(0), REG_32BIT, 0, 0, "XXX_REG"}, 1748 + */ 1749 + XE_WARN_ON(low32_ready); 1718 1750 1719 - group = FIELD_GET(GUC_REGSET_STEERING_GROUP, reg_desc->flags); 1720 - instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, reg_desc->flags); 1721 - dss = xe_gt_mcr_steering_info_to_dss_id(gt, group, instance); 1751 + if (is_ext) { 1752 + int dss, group, instance; 1722 1753 1723 - drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname, dss, value); 1724 - } else { 1725 - drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value); 1754 + group = FIELD_GET(GUC_REGSET_STEERING_GROUP, reg_desc->flags); 1755 + instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, reg_desc->flags); 1756 + dss = xe_gt_mcr_steering_info_to_dss_id(gt, group, instance); 1757 + 1758 + drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname, dss, value); 1759 + } else { 1760 + drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value); 1761 + } 1762 + break; 1726 1763 } 1727 1764 } 1765 + 1766 + /* 1767 + * Incorrect 64bit register order. Possible missing high. 1768 + * for example: 1769 + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, 1770 + * } // <- Register list end 1771 + */ 1772 + XE_WARN_ON(low32_ready); 1728 1773 } 1729 1774 1730 1775 /**
+7
include/drm/display/drm_dp_mst_helper.h
··· 700 700 bool payload_id_table_cleared : 1; 701 701 702 702 /** 703 + * @reset_rx_state: The down request's reply and up request message 704 + * receiver state must be reset, after the topology manager got 705 + * removed. Protected by @lock. 706 + */ 707 + bool reset_rx_state : 1; 708 + 709 + /** 703 710 * @payload_count: The number of currently active payloads in hardware. This value is only 704 711 * intended to be used internally by MST helpers for payload tracking, and is only safe to 705 712 * read/write from the atomic commit (not check) context.