Commit | Line | Data |
---|---|---|
dd08ebf6 MB |
1 | // SPDX-License-Identifier: MIT |
2 | /* | |
3 | * Copyright © 2022 Intel Corporation | |
4 | */ | |
5 | ||
ea9f879d LDM |
6 | #include "xe_gt_topology.h" |
7 | ||
dd08ebf6 MB |
8 | #include <linux/bitmap.h> |
9 | ||
8cb49012 | 10 | #include "regs/xe_gt_regs.h" |
dd08ebf6 | 11 | #include "xe_gt.h" |
dd08ebf6 MB |
12 | #include "xe_mmio.h" |
13 | ||
14 | #define XE_MAX_DSS_FUSE_BITS (32 * XE_MAX_DSS_FUSE_REGS) | |
15 | #define XE_MAX_EU_FUSE_BITS (32 * XE_MAX_EU_FUSE_REGS) | |
16 | ||
dd08ebf6 MB |
17 | static void |
18 | load_dss_mask(struct xe_gt *gt, xe_dss_mask_t mask, int numregs, ...) | |
19 | { | |
20 | va_list argp; | |
21 | u32 fuse_val[XE_MAX_DSS_FUSE_REGS] = {}; | |
22 | int i; | |
23 | ||
24 | if (drm_WARN_ON(>_to_xe(gt)->drm, numregs > XE_MAX_DSS_FUSE_REGS)) | |
25 | numregs = XE_MAX_DSS_FUSE_REGS; | |
26 | ||
27 | va_start(argp, numregs); | |
28 | for (i = 0; i < numregs; i++) | |
ce8bf5bd | 29 | fuse_val[i] = xe_mmio_read32(gt, va_arg(argp, struct xe_reg)); |
dd08ebf6 MB |
30 | va_end(argp); |
31 | ||
32 | bitmap_from_arr32(mask, fuse_val, numregs * 32); | |
33 | } | |
34 | ||
35 | static void | |
36 | load_eu_mask(struct xe_gt *gt, xe_eu_mask_t mask) | |
37 | { | |
38 | struct xe_device *xe = gt_to_xe(gt); | |
ce8bf5bd | 39 | u32 reg_val = xe_mmio_read32(gt, XELP_EU_ENABLE); |
dd08ebf6 MB |
40 | u32 val = 0; |
41 | int i; | |
42 | ||
43 | BUILD_BUG_ON(XE_MAX_EU_FUSE_REGS > 1); | |
44 | ||
45 | /* | |
46 | * Pre-Xe_HP platforms inverted the bit meaning (disable instead | |
47 | * of enable). | |
48 | */ | |
49 | if (GRAPHICS_VERx100(xe) < 1250) | |
ce8bf5bd | 50 | reg_val = ~reg_val & XELP_EU_MASK; |
dd08ebf6 MB |
51 | |
52 | /* On PVC, one bit = one EU */ | |
53 | if (GRAPHICS_VERx100(xe) == 1260) { | |
ce8bf5bd | 54 | val = reg_val; |
dd08ebf6 MB |
55 | } else { |
56 | /* All other platforms, one bit = 2 EU */ | |
ce8bf5bd LDM |
57 | for (i = 0; i < fls(reg_val); i++) |
58 | if (reg_val & BIT(i)) | |
dd08ebf6 MB |
59 | val |= 0x3 << 2 * i; |
60 | } | |
61 | ||
62 | bitmap_from_arr32(mask, &val, XE_MAX_EU_FUSE_BITS); | |
63 | } | |
64 | ||
13fb0c98 MR |
65 | static void |
66 | get_num_dss_regs(struct xe_device *xe, int *geometry_regs, int *compute_regs) | |
67 | { | |
015906ff MR |
68 | if (GRAPHICS_VER(xe) > 20) { |
69 | *geometry_regs = 3; | |
70 | *compute_regs = 3; | |
71 | } else if (GRAPHICS_VERx100(xe) == 1260) { | |
13fb0c98 MR |
72 | *geometry_regs = 0; |
73 | *compute_regs = 2; | |
74 | } else if (GRAPHICS_VERx100(xe) >= 1250) { | |
75 | *geometry_regs = 1; | |
76 | *compute_regs = 1; | |
77 | } else { | |
78 | *geometry_regs = 1; | |
79 | *compute_regs = 0; | |
80 | } | |
81 | } | |
82 | ||
dd08ebf6 MB |
83 | void |
84 | xe_gt_topology_init(struct xe_gt *gt) | |
85 | { | |
86 | struct xe_device *xe = gt_to_xe(gt); | |
e7835e02 | 87 | struct drm_printer p; |
dd08ebf6 MB |
88 | int num_geometry_regs, num_compute_regs; |
89 | ||
13fb0c98 | 90 | get_num_dss_regs(xe, &num_geometry_regs, &num_compute_regs); |
dd08ebf6 | 91 | |
13fb0c98 MR |
92 | /* |
93 | * Register counts returned shouldn't exceed the number of registers | |
94 | * passed as parameters below. | |
95 | */ | |
015906ff MR |
96 | drm_WARN_ON(&xe->drm, num_geometry_regs > 3); |
97 | drm_WARN_ON(&xe->drm, num_compute_regs > 3); | |
13fb0c98 MR |
98 | |
99 | load_dss_mask(gt, gt->fuse_topo.g_dss_mask, | |
100 | num_geometry_regs, | |
015906ff MR |
101 | XELP_GT_GEOMETRY_DSS_ENABLE, |
102 | XE2_GT_GEOMETRY_DSS_1, | |
103 | XE2_GT_GEOMETRY_DSS_2); | |
dd08ebf6 | 104 | load_dss_mask(gt, gt->fuse_topo.c_dss_mask, num_compute_regs, |
ce8bf5bd | 105 | XEHP_GT_COMPUTE_DSS_ENABLE, |
015906ff MR |
106 | XEHPC_GT_COMPUTE_DSS_ENABLE_EXT, |
107 | XE2_GT_COMPUTE_DSS_2); | |
dd08ebf6 MB |
108 | load_eu_mask(gt, gt->fuse_topo.eu_mask_per_dss); |
109 | ||
e7835e02 JN |
110 | p = drm_dbg_printer(>_to_xe(gt)->drm, DRM_UT_DRIVER, "GT topology"); |
111 | ||
dd08ebf6 MB |
112 | xe_gt_topology_dump(gt, &p); |
113 | } | |
114 | ||
dd08ebf6 MB |
115 | void |
116 | xe_gt_topology_dump(struct xe_gt *gt, struct drm_printer *p) | |
117 | { | |
118 | drm_printf(p, "dss mask (geometry): %*pb\n", XE_MAX_DSS_FUSE_BITS, | |
119 | gt->fuse_topo.g_dss_mask); | |
120 | drm_printf(p, "dss mask (compute): %*pb\n", XE_MAX_DSS_FUSE_BITS, | |
121 | gt->fuse_topo.c_dss_mask); | |
122 | ||
123 | drm_printf(p, "EU mask per DSS: %*pb\n", XE_MAX_EU_FUSE_BITS, | |
124 | gt->fuse_topo.eu_mask_per_dss); | |
125 | ||
126 | } | |
127 | ||
128 | /* | |
129 | * Used to obtain the index of the first DSS. Can start searching from the | |
130 | * beginning of a specific dss group (e.g., gslice, cslice, etc.) if | |
131 | * groupsize and groupnum are non-zero. | |
132 | */ | |
133 | unsigned int | |
1415283b | 134 | xe_dss_mask_group_ffs(const xe_dss_mask_t mask, int groupsize, int groupnum) |
dd08ebf6 MB |
135 | { |
136 | return find_next_bit(mask, XE_MAX_DSS_FUSE_BITS, groupnum * groupsize); | |
137 | } | |
13fb0c98 | 138 | |
d0e2dd76 MW |
139 | bool xe_dss_mask_empty(const xe_dss_mask_t mask) |
140 | { | |
141 | return bitmap_empty(mask, XE_MAX_DSS_FUSE_BITS); | |
142 | } | |
143 | ||
13fb0c98 MR |
144 | /** |
145 | * xe_gt_topology_has_dss_in_quadrant - check fusing of DSS in GT quadrant | |
146 | * @gt: GT to check | |
147 | * @quad: Which quadrant of the DSS space to check | |
148 | * | |
149 | * Since Xe_HP platforms can have up to four CCS engines, those engines | |
150 | * are each logically associated with a quarter of the possible DSS. If there | |
151 | * are no DSS present in one of the four quadrants of the DSS space, the | |
152 | * corresponding CCS engine is also not available for use. | |
153 | * | |
154 | * Returns false if all DSS in a quadrant of the GT are fused off, else true. | |
155 | */ | |
156 | bool xe_gt_topology_has_dss_in_quadrant(struct xe_gt *gt, int quad) | |
157 | { | |
158 | struct xe_device *xe = gt_to_xe(gt); | |
159 | xe_dss_mask_t all_dss; | |
160 | int g_dss_regs, c_dss_regs, dss_per_quad, quad_first; | |
161 | ||
162 | bitmap_or(all_dss, gt->fuse_topo.g_dss_mask, gt->fuse_topo.c_dss_mask, | |
163 | XE_MAX_DSS_FUSE_BITS); | |
164 | ||
165 | get_num_dss_regs(xe, &g_dss_regs, &c_dss_regs); | |
166 | dss_per_quad = 32 * max(g_dss_regs, c_dss_regs) / 4; | |
167 | ||
168 | quad_first = xe_dss_mask_group_ffs(all_dss, dss_per_quad, quad); | |
169 | ||
170 | return quad_first < (quad + 1) * dss_per_quad; | |
171 | } |