Skip to content

Commit 2c402a8

Browse files
mjruhlij-intel
authored andcommitted
platform/x86/intel/pmt: support BMG crashlog
The Battlemage GPU has the type 1 version 2 crashlog feature. Update the crashlog driver to support this crashlog version. Signed-off-by: Michael J. Ruhl <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ij: make crashlog_type1_ver2 static] Reviewed-by: Ilpo Järvinen <[email protected]> Signed-off-by: Ilpo Järvinen <[email protected]>
1 parent 5623fa6 commit 2c402a8

File tree

1 file changed

+249
-13
lines changed

1 file changed

+249
-13
lines changed

drivers/platform/x86/intel/pmt/crashlog.c

Lines changed: 249 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,25 +53,59 @@
5353
#define TYPE1_VER0_COMPLETE BIT(31)
5454
#define TYPE1_VER0_TRIGGER_MASK GENMASK(31, 28)
5555

56+
/*
57+
* Type 1 Version 2
58+
* status and control are different registers
59+
*/
60+
#define TYPE1_VER2_STATUS_OFFSET 0x00
61+
#define TYPE1_VER2_CONTROL_OFFSET 0x14
62+
63+
/* status register */
64+
#define TYPE1_VER2_CLEAR_SUPPORT BIT(20)
65+
#define TYPE1_VER2_REARMED BIT(25)
66+
#define TYPE1_VER2_ERROR BIT(26)
67+
#define TYPE1_VER2_CONSUMED BIT(27)
68+
#define TYPE1_VER2_DISABLED BIT(28)
69+
#define TYPE1_VER2_CLEARED BIT(29)
70+
#define TYPE1_VER2_IN_PROGRESS BIT(30)
71+
#define TYPE1_VER2_COMPLETE BIT(31)
72+
73+
/* control register */
74+
#define TYPE1_VER2_CONSUME BIT(25)
75+
#define TYPE1_VER2_REARM BIT(28)
76+
#define TYPE1_VER2_EXECUTE BIT(29)
77+
#define TYPE1_VER2_CLEAR BIT(30)
78+
#define TYPE1_VER2_DISABLE BIT(31)
79+
#define TYPE1_VER2_TRIGGER_MASK \
80+
(TYPE1_VER2_EXECUTE | TYPE1_VER2_CLEAR | TYPE1_VER2_DISABLE)
81+
5682
/* After offset, order alphabetically, not bit ordered */
5783
struct crashlog_status {
5884
u32 offset;
85+
u32 clear_supported;
5986
u32 cleared;
6087
u32 complete;
88+
u32 consumed;
6189
u32 disabled;
90+
u32 error;
91+
u32 in_progress;
92+
u32 rearmed;
6293
};
6394

6495
struct crashlog_control {
6596
u32 offset;
6697
u32 trigger_mask;
6798
u32 clear;
99+
u32 consume;
68100
u32 disable;
69101
u32 manual;
102+
u32 rearm;
70103
};
71104

72105
struct crashlog_info {
73106
const struct crashlog_status status;
74107
const struct crashlog_control control;
108+
const struct attribute_group *attr_grp;
75109
};
76110

77111
struct crashlog_entry {
@@ -128,19 +162,23 @@ static bool pmt_crashlog_disabled(struct crashlog_entry *crashlog)
128162
return pmt_crashlog_rc(crashlog, crashlog->info->status.disabled);
129163
}
130164

131-
static bool pmt_crashlog_supported(struct intel_pmt_entry *entry)
165+
static bool pmt_crashlog_supported(struct intel_pmt_entry *entry, u32 *crash_type, u32 *version)
132166
{
133167
u32 discovery_header = readl(entry->disc_table + CONTROL_OFFSET);
134-
u32 crash_type, version;
135168

136-
crash_type = GET_TYPE(discovery_header);
137-
version = GET_VERSION(discovery_header);
169+
*crash_type = GET_TYPE(discovery_header);
170+
*version = GET_VERSION(discovery_header);
138171

139172
/*
140-
* Currently we only recognize OOBMSM version 0 devices.
141-
* We can ignore all other crashlog devices in the system.
173+
* Currently we only recognize OOBMSM (type 1) and version 0 or 2
174+
* devices.
175+
*
176+
* Ignore all other crashlog devices in the system.
142177
*/
143-
return crash_type == CRASH_TYPE_OOBMSM && version == 0;
178+
if (*crash_type == CRASH_TYPE_OOBMSM && (*version == 0 || *version == 2))
179+
return true;
180+
181+
return false;
144182
}
145183

146184
static void pmt_crashlog_set_disable(struct crashlog_entry *crashlog,
@@ -159,9 +197,115 @@ static void pmt_crashlog_set_execute(struct crashlog_entry *crashlog)
159197
pmt_crashlog_rmw(crashlog, crashlog->info->control.manual, true);
160198
}
161199

200+
static bool pmt_crashlog_cleared(struct crashlog_entry *crashlog)
201+
{
202+
return pmt_crashlog_rc(crashlog, crashlog->info->status.cleared);
203+
}
204+
205+
static bool pmt_crashlog_consumed(struct crashlog_entry *crashlog)
206+
{
207+
return pmt_crashlog_rc(crashlog, crashlog->info->status.consumed);
208+
}
209+
210+
static void pmt_crashlog_set_consumed(struct crashlog_entry *crashlog)
211+
{
212+
pmt_crashlog_rmw(crashlog, crashlog->info->control.consume, true);
213+
}
214+
215+
static bool pmt_crashlog_error(struct crashlog_entry *crashlog)
216+
{
217+
return pmt_crashlog_rc(crashlog, crashlog->info->status.error);
218+
}
219+
220+
static bool pmt_crashlog_rearm(struct crashlog_entry *crashlog)
221+
{
222+
return pmt_crashlog_rc(crashlog, crashlog->info->status.rearmed);
223+
}
224+
225+
static void pmt_crashlog_set_rearm(struct crashlog_entry *crashlog)
226+
{
227+
pmt_crashlog_rmw(crashlog, crashlog->info->control.rearm, true);
228+
}
229+
162230
/*
163231
* sysfs
164232
*/
233+
static ssize_t
234+
clear_show(struct device *dev, struct device_attribute *attr, char *buf)
235+
{
236+
struct crashlog_entry *crashlog = dev_get_drvdata(dev);
237+
bool cleared = pmt_crashlog_cleared(crashlog);
238+
239+
return sysfs_emit(buf, "%d\n", cleared);
240+
}
241+
242+
static ssize_t
243+
clear_store(struct device *dev, struct device_attribute *attr,
244+
const char *buf, size_t count)
245+
{
246+
struct crashlog_entry *crashlog;
247+
bool clear;
248+
int result;
249+
250+
crashlog = dev_get_drvdata(dev);
251+
252+
result = kstrtobool(buf, &clear);
253+
if (result)
254+
return result;
255+
256+
/* set bit only */
257+
if (!clear)
258+
return -EINVAL;
259+
260+
guard(mutex)(&crashlog->control_mutex);
261+
262+
pmt_crashlog_set_clear(crashlog);
263+
264+
return count;
265+
}
266+
static DEVICE_ATTR_RW(clear);
267+
268+
static ssize_t
269+
consumed_show(struct device *dev, struct device_attribute *attr, char *buf)
270+
{
271+
struct crashlog_entry *crashlog = dev_get_drvdata(dev);
272+
bool consumed = pmt_crashlog_consumed(crashlog);
273+
274+
return sysfs_emit(buf, "%d\n", consumed);
275+
}
276+
277+
static ssize_t
278+
consumed_store(struct device *dev, struct device_attribute *attr, const char *buf,
279+
size_t count)
280+
{
281+
struct crashlog_entry *crashlog;
282+
bool consumed;
283+
int result;
284+
285+
crashlog = dev_get_drvdata(dev);
286+
287+
result = kstrtobool(buf, &consumed);
288+
if (result)
289+
return result;
290+
291+
/* set bit only */
292+
if (!consumed)
293+
return -EINVAL;
294+
295+
guard(mutex)(&crashlog->control_mutex);
296+
297+
if (pmt_crashlog_disabled(crashlog))
298+
return -EBUSY;
299+
300+
if (!pmt_crashlog_complete(crashlog))
301+
return -EEXIST;
302+
303+
pmt_crashlog_set_consumed(crashlog);
304+
305+
return count;
306+
}
307+
static DEVICE_ATTR_RW(consumed);
308+
165309
static ssize_t
166310
enable_show(struct device *dev, struct device_attribute *attr, char *buf)
167311
{
@@ -193,6 +337,51 @@ enable_store(struct device *dev, struct device_attribute *attr,
193337
}
194338
static DEVICE_ATTR_RW(enable);
195339

340+
static ssize_t
341+
error_show(struct device *dev, struct device_attribute *attr, char *buf)
342+
{
343+
struct crashlog_entry *crashlog = dev_get_drvdata(dev);
344+
bool error = pmt_crashlog_error(crashlog);
345+
346+
return sysfs_emit(buf, "%d\n", error);
347+
}
348+
static DEVICE_ATTR_RO(error);
349+
350+
static ssize_t
351+
rearm_show(struct device *dev, struct device_attribute *attr, char *buf)
352+
{
353+
struct crashlog_entry *crashlog = dev_get_drvdata(dev);
354+
int rearmed = pmt_crashlog_rearm(crashlog);
355+
356+
return sysfs_emit(buf, "%d\n", rearmed);
357+
}
358+
359+
static ssize_t
360+
rearm_store(struct device *dev, struct device_attribute *attr, const char *buf,
361+
size_t count)
362+
{
363+
struct crashlog_entry *crashlog;
364+
bool rearm;
365+
int result;
366+
367+
crashlog = dev_get_drvdata(dev);
368+
369+
result = kstrtobool(buf, &rearm);
370+
if (result)
371+
return result;
372+
373+
/* set only */
374+
if (!rearm)
375+
return -EINVAL;
376+
377+
guard(mutex)(&crashlog->control_mutex);
378+
379+
pmt_crashlog_set_rearm(crashlog);
380+
381+
return count;
382+
}
383+
static DEVICE_ATTR_RW(rearm);
384+
196385
static ssize_t
197386
trigger_show(struct device *dev, struct device_attribute *attr, char *buf)
198387
{
@@ -240,14 +429,28 @@ trigger_store(struct device *dev, struct device_attribute *attr,
240429
}
241430
static DEVICE_ATTR_RW(trigger);
242431

243-
static struct attribute *pmt_crashlog_attrs[] = {
432+
static struct attribute *pmt_crashlog_type1_ver0_attrs[] = {
244433
&dev_attr_enable.attr,
245434
&dev_attr_trigger.attr,
246435
NULL
247436
};
248437

249-
static const struct attribute_group pmt_crashlog_group = {
250-
.attrs = pmt_crashlog_attrs,
438+
static struct attribute *pmt_crashlog_type1_ver2_attrs[] = {
439+
&dev_attr_clear.attr,
440+
&dev_attr_consumed.attr,
441+
&dev_attr_enable.attr,
442+
&dev_attr_error.attr,
443+
&dev_attr_rearm.attr,
444+
&dev_attr_trigger.attr,
445+
NULL
446+
};
447+
448+
static const struct attribute_group pmt_crashlog_type1_ver0_group = {
449+
.attrs = pmt_crashlog_type1_ver0_attrs,
450+
};
451+
452+
static const struct attribute_group pmt_crashlog_type1_ver2_group = {
453+
.attrs = pmt_crashlog_type1_ver2_attrs,
251454
};
252455

253456
static const struct crashlog_info crashlog_type1_ver0 = {
@@ -261,22 +464,55 @@ static const struct crashlog_info crashlog_type1_ver0 = {
261464
.control.clear = TYPE1_VER0_CLEAR,
262465
.control.disable = TYPE1_VER0_DISABLE,
263466
.control.manual = TYPE1_VER0_EXECUTE,
467+
.attr_grp = &pmt_crashlog_type1_ver0_group,
264468
};
265469

470+
static const struct crashlog_info crashlog_type1_ver2 = {
471+
.status.offset = TYPE1_VER2_STATUS_OFFSET,
472+
.status.clear_supported = TYPE1_VER2_CLEAR_SUPPORT,
473+
.status.cleared = TYPE1_VER2_CLEARED,
474+
.status.complete = TYPE1_VER2_COMPLETE,
475+
.status.consumed = TYPE1_VER2_CONSUMED,
476+
.status.disabled = TYPE1_VER2_DISABLED,
477+
.status.error = TYPE1_VER2_ERROR,
478+
.status.in_progress = TYPE1_VER2_IN_PROGRESS,
479+
.status.rearmed = TYPE1_VER2_REARMED,
480+
481+
.control.offset = TYPE1_VER2_CONTROL_OFFSET,
482+
.control.trigger_mask = TYPE1_VER2_TRIGGER_MASK,
483+
.control.clear = TYPE1_VER2_CLEAR,
484+
.control.consume = TYPE1_VER2_CONSUME,
485+
.control.disable = TYPE1_VER2_DISABLE,
486+
.control.manual = TYPE1_VER2_EXECUTE,
487+
.control.rearm = TYPE1_VER2_REARM,
488+
.attr_grp = &pmt_crashlog_type1_ver2_group,
489+
};
490+
491+
static const struct crashlog_info *select_crashlog_info(u32 type, u32 version)
492+
{
493+
if (version == 0)
494+
return &crashlog_type1_ver0;
495+
496+
return &crashlog_type1_ver2;
497+
}
498+
266499
static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry,
267500
struct device *dev)
268501
{
269502
void __iomem *disc_table = entry->disc_table;
270503
struct intel_pmt_header *header = &entry->header;
271504
struct crashlog_entry *crashlog;
505+
u32 version;
506+
u32 type;
272507

273-
if (!pmt_crashlog_supported(entry))
508+
if (!pmt_crashlog_supported(entry, &type, &version))
274509
return 1;
275510

276511
/* initialize the crashlog struct */
277512
crashlog = container_of(entry, struct crashlog_entry, entry);
278513
mutex_init(&crashlog->control_mutex);
279-
crashlog->info = &crashlog_type1_ver0;
514+
515+
crashlog->info = select_crashlog_info(type, version);
280516

281517
header->access_type = GET_ACCESS(readl(disc_table));
282518
header->guid = readl(disc_table + GUID_OFFSET);
@@ -285,7 +521,7 @@ static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry,
285521
/* Size is measured in DWORDS, but accessor returns bytes */
286522
header->size = GET_SIZE(readl(disc_table + SIZE_OFFSET));
287523

288-
entry->attr_grp = &pmt_crashlog_group;
524+
entry->attr_grp = crashlog->info->attr_grp;
289525

290526
return 0;
291527
}

0 commit comments

Comments
 (0)