mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook <kees+treewide@kernel.org>
198 lines
4.3 KiB
C
198 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2026 Intel Corporation.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/dev_printk.h>
|
|
#include <linux/err.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/pci_ids.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
#include "regs/xe_i2c_regs.h"
|
|
|
|
#include "xe_amc.h"
|
|
#include "xe_device.h"
|
|
#include "xe_i2c.h"
|
|
#include "xe_mmio.h"
|
|
|
|
/**
|
|
* DOC: Add-In Management Controller (AMC)
|
|
*
|
|
* Handler for the SMBus Alerts from the AMC. All the alerts from AMC will cause
|
|
* the device to be declared wedged.
|
|
*/
|
|
|
|
#define AMC_COMMAND 0x0f
|
|
#define AMC_GPU_I2C_ADDR 0x8f
|
|
#define AMC_VERSION_V1 0x01
|
|
#define AMC_DESTINATION_ID 12
|
|
#define AMC_SOURCE_ID 8
|
|
#define AMC_FLAGS 0xc8
|
|
|
|
#define AMC_MSG_TYPE 0x7e
|
|
#define AMC_GET_ALERT_REASON 0x01
|
|
|
|
enum xe_amc_alert {
|
|
AMC_ALERT_UNKNOWN,
|
|
AMC_ALERT_FW_DOWNLOAD,
|
|
AMC_ALERT_THERMAL_TRIP,
|
|
AMC_ALERT_OOB_REQUEST,
|
|
AMC_ALERT_OOB_RESET,
|
|
AMC_ALERT_CATERR,
|
|
};
|
|
|
|
static const char * const amc_alert[] = {
|
|
[AMC_ALERT_FW_DOWNLOAD] = "Firmware Download",
|
|
[AMC_ALERT_THERMAL_TRIP] = "Thermal Trip",
|
|
[AMC_ALERT_OOB_REQUEST] = "OOB Request",
|
|
[AMC_ALERT_OOB_RESET] = "OOB Reset",
|
|
[AMC_ALERT_CATERR] = "Catastrophic",
|
|
};
|
|
|
|
struct xe_amc {
|
|
struct xe_i2c *i2c;
|
|
struct work_struct work;
|
|
};
|
|
|
|
struct amc_header {
|
|
u8 command;
|
|
u8 len;
|
|
u8 address;
|
|
u8 version;
|
|
u8 destination;
|
|
u8 source;
|
|
u8 flags;
|
|
} __packed;
|
|
|
|
struct amc_message {
|
|
u8 type;
|
|
u16 vendor;
|
|
u8 command;
|
|
} __packed;
|
|
|
|
struct amc_request {
|
|
struct amc_header header;
|
|
struct amc_message message;
|
|
u32 reserved;
|
|
} __packed;
|
|
|
|
struct amc_response {
|
|
struct amc_header header;
|
|
struct amc_message message;
|
|
u8 error;
|
|
u8 value;
|
|
} __packed;
|
|
|
|
static const struct amc_request amc_get_alert_reason = {
|
|
.header = {
|
|
.command = AMC_COMMAND,
|
|
.len = sizeof(struct amc_request) - 2,
|
|
.address = AMC_GPU_I2C_ADDR,
|
|
.version = AMC_VERSION_V1,
|
|
.destination = AMC_DESTINATION_ID,
|
|
.source = AMC_SOURCE_ID,
|
|
.flags = AMC_FLAGS,
|
|
},
|
|
.message = {
|
|
.type = AMC_MSG_TYPE,
|
|
.vendor = htons(PCI_VENDOR_ID_INTEL),
|
|
.command = AMC_GET_ALERT_REASON,
|
|
},
|
|
};
|
|
|
|
static void xe_amc_work(struct work_struct *work)
|
|
{
|
|
const struct amc_request *request = &amc_get_alert_reason;
|
|
struct xe_amc *amc = from_work(amc, work, work);
|
|
u8 alert_reason = AMC_ALERT_UNKNOWN;
|
|
struct amc_response response;
|
|
struct i2c_client *client;
|
|
int ret;
|
|
|
|
client = amc->i2c->client[XE_I2C_CLIENT_AMC];
|
|
if (IS_ERR_OR_NULL(client))
|
|
goto out_reassert_interrupt;
|
|
|
|
ret = i2c_master_send(client, (u8 *)request, sizeof(*request));
|
|
if (ret < 0) {
|
|
dev_err(&client->dev, "failed to send request (%d)\n", ret);
|
|
goto out_reassert_interrupt;
|
|
}
|
|
|
|
/* AMC needs 20ms to generate the response. */
|
|
fsleep(20 * USEC_PER_MSEC);
|
|
|
|
ret = i2c_master_recv(client, (u8 *)&response, sizeof(response));
|
|
if (ret < 0) {
|
|
dev_err(&client->dev, "failed to read response (%d)\n", ret);
|
|
goto out_reassert_interrupt;
|
|
}
|
|
|
|
if (!response.header.len) {
|
|
dev_err(&client->dev, "empty response from AMC\n");
|
|
goto out_reassert_interrupt;
|
|
}
|
|
|
|
if (memcmp(&response.message, &request->message, sizeof(struct amc_message))) {
|
|
dev_err(&client->dev, "response does not match the request\n");
|
|
goto out_reassert_interrupt;
|
|
}
|
|
|
|
if (response.error) {
|
|
dev_err(&client->dev, "AMC error 0x%02x\n", response.error);
|
|
goto out_reassert_interrupt;
|
|
}
|
|
|
|
alert_reason = response.value;
|
|
dev_dbg(&client->dev, "Alert reason: %d\n", alert_reason);
|
|
|
|
out_reassert_interrupt:
|
|
xe_mmio_rmw32(amc->i2c->mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0);
|
|
|
|
switch (alert_reason) {
|
|
case AMC_ALERT_FW_DOWNLOAD:
|
|
case AMC_ALERT_THERMAL_TRIP:
|
|
case AMC_ALERT_OOB_REQUEST:
|
|
case AMC_ALERT_OOB_RESET:
|
|
case AMC_ALERT_CATERR:
|
|
dev_warn(amc->i2c->drm_dev, "AMC Alert: %s\n", amc_alert[alert_reason]);
|
|
xe_device_declare_wedged(i2c_client_to_xe_device(client));
|
|
break;
|
|
default:
|
|
dev_warn(amc->i2c->drm_dev, "unknown AMC alert: %d\n", alert_reason);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void xe_amc_handle_alert(struct xe_i2c *i2c)
|
|
{
|
|
queue_work(system_long_wq, &i2c->amc->work);
|
|
}
|
|
|
|
int xe_amc_init(struct xe_i2c *i2c)
|
|
{
|
|
struct xe_amc *amc;
|
|
|
|
amc = kzalloc_obj(*amc);
|
|
if (!amc)
|
|
return -ENOMEM;
|
|
|
|
INIT_WORK(&amc->work, xe_amc_work);
|
|
i2c->amc = amc;
|
|
amc->i2c = i2c;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void xe_amc_exit(struct xe_i2c *i2c)
|
|
{
|
|
if (i2c->amc) {
|
|
cancel_work_sync(&i2c->amc->work);
|
|
kfree(i2c->amc);
|
|
}
|
|
}
|