drm/i915 fixes for v5.19-rc3: - Fix page fault on error state read - Fix memory leaks in per-gt sysfs - Fix multiple fence handling - Remove accidental static from a local variable
Unified · Split
| @@ -999,7 +999,8 @@ static int eb_validate_vmas(struct i915_execbuffer *eb) · 998 unmodified lines | |||
| 999 | } | 999 | } |
| 1000 | } | 1000 | } |
| 1001 | 1001 | ||
| 1002 | err = dma_resv_reserve_fences(vma->obj->base.resv, 1); | 1002 | /* Reserve enough slots to accommodate composite fences */ |
| 1003 | err = dma_resv_reserve_fences(vma->obj->base.resv, eb->num_batches); | ||
| 1003 | if (err) | 1004 | if (err) |
| 1004 | return err; | 1005 | return err; |
| 1005 | 1006 | ||
| @@ -785,6 +785,7 @@ void intel_gt_driver_unregister(struct intel_gt *gt) · 784 unmodified lines | |||
| 785 | { | 785 | { |
| 786 | intel_wakeref_t wakeref; | 786 | intel_wakeref_t wakeref; |
| 787 | 787 | ||
| 788 | intel_gt_sysfs_unregister(gt); | ||
| 788 | intel_rps_driver_unregister(>->rps); | 789 | intel_rps_driver_unregister(>->rps); |
| 789 | intel_gsc_fini(>->gsc); | 790 | intel_gsc_fini(>->gsc); |
| 790 | 791 | ||
| @@ -24,7 +24,7 @@ bool is_object_gt(struct kobject *kobj) · 23 unmodified lines | |||
| 24 | 24 | ||
| 25 | static struct intel_gt *kobj_to_gt(struct kobject *kobj) | 25 | static struct intel_gt *kobj_to_gt(struct kobject *kobj) |
| 26 | { | 26 | { |
| 27 | return container_of(kobj, struct kobj_gt, base)->gt; | 27 | return container_of(kobj, struct intel_gt, sysfs_gt); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev, | 30 | struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev, |
| @@ -72,9 +72,9 @@ static struct attribute *id_attrs[] = { · 41 unmodified lines | |||
| 72 | }; | 72 | }; |
| 73 | ATTRIBUTE_GROUPS(id); | 73 | ATTRIBUTE_GROUPS(id); |
| 74 | 74 | ||
| 75 | /* A kobject needs a release() method even if it does nothing */ | ||
| 75 | static void kobj_gt_release(struct kobject *kobj) | 76 | static void kobj_gt_release(struct kobject *kobj) |
| 76 | { | 77 | { |
| 77 | kfree(kobj); | ||
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static struct kobj_type kobj_gt_type = { | 80 | static struct kobj_type kobj_gt_type = { |
| @@ -85,8 +85,6 @@ static struct kobj_type kobj_gt_type = { · 4 unmodified lines | |||
| 85 | 85 | ||
| 86 | void intel_gt_sysfs_register(struct intel_gt *gt) | 86 | void intel_gt_sysfs_register(struct intel_gt *gt) |
| 87 | { | 87 | { |
| 88 | struct kobj_gt *kg; | ||
| 89 | |||
| 90 | /* | 88 | /* |
| 91 | * We need to make things right with the | 89 | * We need to make things right with the |
| 92 | * ABI compatibility. The files were originally | 90 | * ABI compatibility. The files were originally |
| @@ -98,25 +96,22 @@ void intel_gt_sysfs_register(struct intel_gt *gt) · 5 unmodified lines | |||
| 98 | if (gt_is_root(gt)) | 96 | if (gt_is_root(gt)) |
| 99 | intel_gt_sysfs_pm_init(gt, gt_get_parent_obj(gt)); | 97 | intel_gt_sysfs_pm_init(gt, gt_get_parent_obj(gt)); |
| 100 | 98 | ||
| 101 | kg = kzalloc(sizeof(*kg), GFP_KERNEL); | 99 | /* init and xfer ownership to sysfs tree */ |
| 102 | if (!kg) | 100 | if (kobject_init_and_add(>->sysfs_gt, &kobj_gt_type, |
| 101 | gt->i915->sysfs_gt, "gt%d", gt->info.id)) | ||
| 103 | goto exit_fail; | 102 | goto exit_fail; |
| 104 | 103 | ||
| 105 | kobject_init(&kg->base, &kobj_gt_type); | 104 | intel_gt_sysfs_pm_init(gt, >->sysfs_gt); |
| 106 | kg->gt = gt; | ||
| 107 | |||
| 108 | /* xfer ownership to sysfs tree */ | ||
| 109 | if (kobject_add(&kg->base, gt->i915->sysfs_gt, "gt%d", gt->info.id)) | ||
| 110 | goto exit_kobj_put; | ||
| 111 | |||
| 112 | intel_gt_sysfs_pm_init(gt, &kg->base); | ||
| 113 | 105 | ||
| 114 | return; | 106 | return; |
| 115 | 107 | ||
| 116 | exit_kobj_put: | ||
| 117 | kobject_put(&kg->base); | ||
| 118 | |||
| 119 | exit_fail: | 108 | exit_fail: |
| 109 | kobject_put(>->sysfs_gt); | ||
| 120 | drm_warn(>->i915->drm, | 110 | drm_warn(>->i915->drm, |
| 121 | "failed to initialize gt%d sysfs root\n", gt->info.id); | 111 | "failed to initialize gt%d sysfs root\n", gt->info.id); |
| 122 | } | 112 | } |
| 113 | |||
| 114 | void intel_gt_sysfs_unregister(struct intel_gt *gt) | ||
| 115 | { | ||
| 116 | kobject_put(>->sysfs_gt); | ||
| 117 | } | ||
| @@ -13,11 +13,6 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | struct intel_gt; | 14 | struct intel_gt; |
| 15 | 15 | ||
| 16 | struct kobj_gt { | ||
| 17 | struct kobject base; | ||
| 18 | struct intel_gt *gt; | ||
| 19 | }; | ||
| 20 | |||
| 21 | bool is_object_gt(struct kobject *kobj); | 16 | bool is_object_gt(struct kobject *kobj); |
| 22 | 17 | ||
| 23 | struct drm_i915_private *kobj_to_i915(struct kobject *kobj); | 18 | struct drm_i915_private *kobj_to_i915(struct kobject *kobj); |
| @@ -28,6 +23,7 @@ intel_gt_create_kobj(struct intel_gt *gt, · 4 unmodified lines | |||
| 28 | const char *name); | 23 | const char *name); |
| 29 | 24 | ||
| 30 | void intel_gt_sysfs_register(struct intel_gt *gt); | 25 | void intel_gt_sysfs_register(struct intel_gt *gt); |
| 26 | void intel_gt_sysfs_unregister(struct intel_gt *gt); | ||
| 31 | struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev, | 27 | struct intel_gt *intel_gt_sysfs_get_drvdata(struct device *dev, |
| 32 | const char *name); | 28 | const char *name); |
| 33 | 29 | ||
| @@ -224,6 +224,9 @@ struct intel_gt { · 223 unmodified lines | |||
| 224 | } mocs; | 224 | } mocs; |
| 225 | 225 | ||
| 226 | struct intel_pxp pxp; | 226 | struct intel_pxp pxp; |
| 227 | |||
| 228 | /* gt/gtN sysfs */ | ||
| 229 | struct kobject sysfs_gt; | ||
| 227 | }; | 230 | }; |
| 228 | 231 | ||
| 229 | enum intel_gt_scratch_field { | 232 | enum intel_gt_scratch_field { |
| @@ -156,7 +156,7 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw) · 155 unmodified lines | |||
| 156 | [INTEL_UC_FW_TYPE_GUC] = { blobs_guc, ARRAY_SIZE(blobs_guc) }, | 156 | [INTEL_UC_FW_TYPE_GUC] = { blobs_guc, ARRAY_SIZE(blobs_guc) }, |
| 157 | [INTEL_UC_FW_TYPE_HUC] = { blobs_huc, ARRAY_SIZE(blobs_huc) }, | 157 | [INTEL_UC_FW_TYPE_HUC] = { blobs_huc, ARRAY_SIZE(blobs_huc) }, |
| 158 | }; | 158 | }; |
| 159 | static const struct uc_fw_platform_requirement *fw_blobs; | 159 | const struct uc_fw_platform_requirement *fw_blobs; |
| 160 | enum intel_platform p = INTEL_INFO(i915)->platform; | 160 | enum intel_platform p = INTEL_INFO(i915)->platform; |
| 161 | u32 fw_count; | 161 | u32 fw_count; |
| 162 | u8 rev = INTEL_REVID(i915); | 162 | u8 rev = INTEL_REVID(i915); |
| @@ -166,7 +166,14 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj, · 165 unmodified lines | |||
| 166 | struct device *kdev = kobj_to_dev(kobj); | 166 | struct device *kdev = kobj_to_dev(kobj); |
| 167 | struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); | 167 | struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); |
| 168 | struct i915_gpu_coredump *gpu; | 168 | struct i915_gpu_coredump *gpu; |
| 169 | ssize_t ret; | 169 | ssize_t ret = 0; |
| 170 | |||
| 171 | /* | ||
| 172 | * FIXME: Concurrent clients triggering resets and reading + clearing | ||
| 173 | * dumps can cause inconsistent sysfs reads when a user calls in with a | ||
| 174 | * non-zero offset to complete a prior partial read but the | ||
| 175 | * gpu_coredump has been cleared or replaced. | ||
| 176 | */ | ||
| 170 | 177 | ||
| 171 | gpu = i915_first_error_state(i915); | 178 | gpu = i915_first_error_state(i915); |
| 172 | if (IS_ERR(gpu)) { | 179 | if (IS_ERR(gpu)) { |
| @@ -178,8 +185,10 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj, · 5 unmodified lines | |||
| 178 | const char *str = "No error state collected\n"; | 185 | const char *str = "No error state collected\n"; |
| 179 | size_t len = strlen(str); | 186 | size_t len = strlen(str); |
| 180 | 187 | ||
| 181 | ret = min_t(size_t, count, len - off); | 188 | if (off < len) { |
| 182 | memcpy(buf, str + off, ret); | 189 | ret = min_t(size_t, count, len - off); |
| 190 | memcpy(buf, str + off, ret); | ||
| 191 | } | ||
| 183 | } | 192 | } |
| 184 | 193 | ||
| 185 | return ret; | 194 | return ret; |
| @@ -259,4 +268,6 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv) · 73 unmodified lines | |||
| 259 | 268 | ||
| 260 | device_remove_bin_file(kdev, &dpf_attrs_1); | 269 | device_remove_bin_file(kdev, &dpf_attrs_1); |
| 261 | device_remove_bin_file(kdev, &dpf_attrs); | 270 | device_remove_bin_file(kdev, &dpf_attrs); |
| 271 | |||
| 272 | kobject_put(dev_priv->sysfs_gt); | ||
| 262 | } | 273 | } |
| @@ -23,6 +23,7 @@ · 22 unmodified lines | |||
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <linux/sched/mm.h> | 25 | #include <linux/sched/mm.h> |
| 26 | #include <linux/dma-fence-array.h> | ||
| 26 | #include <drm/drm_gem.h> | 27 | #include <drm/drm_gem.h> |
| 27 | 28 | ||
| 28 | #include "display/intel_frontbuffer.h" | 29 | #include "display/intel_frontbuffer.h" |
| @@ -1823,6 +1824,21 @@ int _i915_vma_move_to_active(struct i915_vma *vma, · 1794 unmodified lines | |||
| 1823 | if (unlikely(err)) | 1824 | if (unlikely(err)) |
| 1824 | return err; | 1825 | return err; |
| 1825 | 1826 | ||
| 1827 | /* | ||
| 1828 | * Reserve fences slot early to prevent an allocation after preparing | ||
| 1829 | * the workload and associating fences with dma_resv. | ||
| 1830 | */ | ||
| 1831 | if (fence && !(flags & __EXEC_OBJECT_NO_RESERVE)) { | ||
| 1832 | struct dma_fence *curr; | ||
| 1833 | int idx; | ||
| 1834 | |||
| 1835 | dma_fence_array_for_each(curr, idx, fence) | ||
| 1836 | ; | ||
| 1837 | err = dma_resv_reserve_fences(vma->obj->base.resv, idx); | ||
| 1838 | if (unlikely(err)) | ||
| 1839 | return err; | ||
| 1840 | } | ||
| 1841 | |||
| 1826 | if (flags & EXEC_OBJECT_WRITE) { | 1842 | if (flags & EXEC_OBJECT_WRITE) { |
| 1827 | struct intel_frontbuffer *front; | 1843 | struct intel_frontbuffer *front; |
| 1828 | 1844 | ||
| @@ -1832,31 +1848,23 @@ int _i915_vma_move_to_active(struct i915_vma *vma, · 3 unmodified lines | |||
| 1832 | i915_active_add_request(&front->write, rq); | 1848 | i915_active_add_request(&front->write, rq); |
| 1833 | intel_frontbuffer_put(front); | 1849 | intel_frontbuffer_put(front); |
| 1834 | } | 1850 | } |
| 1851 | } | ||
| 1835 | 1852 | ||
| 1836 | if (!(flags & __EXEC_OBJECT_NO_RESERVE)) { | 1853 | if (fence) { |
| 1837 | err = dma_resv_reserve_fences(vma->obj->base.resv, 1); | 1854 | struct dma_fence *curr; |
| 1838 | if (unlikely(err)) | 1855 | enum dma_resv_usage usage; |
| 1839 | return err; | 1856 | int idx; |
| 1840 | } | ||
| 1841 | 1857 | ||
| 1842 | if (fence) { | 1858 | obj->read_domains = 0; |
| 1843 | dma_resv_add_fence(vma->obj->base.resv, fence, | 1859 | if (flags & EXEC_OBJECT_WRITE) { |
| 1844 | DMA_RESV_USAGE_WRITE); | 1860 | usage = DMA_RESV_USAGE_WRITE; |
| 1845 | obj->write_domain = I915_GEM_DOMAIN_RENDER; | 1861 | obj->write_domain = I915_GEM_DOMAIN_RENDER; |
| 1846 | obj->read_domains = 0; | 1862 | } else { |
| 1847 | } | 1863 | usage = DMA_RESV_USAGE_READ; |
| 1848 | } else { | ||
| 1849 | if (!(flags & __EXEC_OBJECT_NO_RESERVE)) { | ||
| 1850 | err = dma_resv_reserve_fences(vma->obj->base.resv, 1); | ||
| 1851 | if (unlikely(err)) | ||
| 1852 | return err; | ||
| 1853 | } | 1864 | } |
| 1854 | 1865 | ||
| 1855 | if (fence) { | 1866 | dma_fence_array_for_each(curr, idx, fence) |
| 1856 | dma_resv_add_fence(vma->obj->base.resv, fence, | 1867 | dma_resv_add_fence(vma->obj->base.resv, curr, usage); |
| 1857 | DMA_RESV_USAGE_READ); | ||
| 1858 | obj->write_domain = 0; | ||
| 1859 | } | ||
| 1860 | } | 1868 | } |
| 1861 | 1869 | ||
| 1862 | if (flags & EXEC_OBJECT_NEEDS_FENCE && vma->fence) | 1870 | if (flags & EXEC_OBJECT_NEEDS_FENCE && vma->fence) |