drivers/char/ipmi/ipmi_ipmb.c

Source file repositories/reference/linux-study-clean/drivers/char/ipmi/ipmi_ipmb.c

File Facts

System
Linux kernel
Corpus path
drivers/char/ipmi/ipmi_ipmb.c
Extension
.c
Size
14103 bytes
Lines
589
Domain
Driver Families
Bucket
drivers/char
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ipmi_ipmb_dev {
	struct ipmi_smi *intf;
	struct i2c_client *client;
	struct i2c_client *slave;

	struct ipmi_smi_handlers handlers;

	bool ready;

	u8 curr_seq;

	u8 bmcaddr;
	u32 retry_time_ms;
	u32 max_retries;

	struct ipmi_smi_msg *next_msg;
	struct ipmi_smi_msg *working_msg;

	/* Transmit thread. */
	struct task_struct *thread;
	struct semaphore wake_thread;
	struct semaphore got_rsp;
	spinlock_t lock;
	bool stopping;

	u8 xmitmsg[IPMB_MAX_MSG_LEN];
	unsigned int xmitlen;

	u8 rcvmsg[IPMB_MAX_MSG_LEN];
	unsigned int rcvlen;
	bool overrun;
};

static bool valid_ipmb(struct ipmi_ipmb_dev *iidev)
{
	u8 *msg = iidev->rcvmsg;
	u8 netfn;

	if (iidev->overrun)
		return false;

	/* Minimum message size. */
	if (iidev->rcvlen < 7)
		return false;

	/* Is it a response? */
	netfn = msg[1] >> 2;
	if (netfn & 1) {
		/* Response messages have an added completion code. */
		if (iidev->rcvlen < 8)
			return false;
	}

	if (ipmb_checksum(msg, 3) != 0)
		return false;
	if (ipmb_checksum(msg + 3, iidev->rcvlen - 3) != 0)
		return false;

	return true;
}

static void ipmi_ipmb_check_msg_done(struct ipmi_ipmb_dev *iidev)
{
	struct ipmi_smi_msg *imsg = NULL;
	u8 *msg = iidev->rcvmsg;
	bool is_cmd;
	unsigned long flags;

	if (iidev->rcvlen == 0)
		return;
	if (!valid_ipmb(iidev))
		goto done;

	is_cmd = ((msg[1] >> 2) & 1) == 0;

	if (is_cmd) {
		/* Ignore commands until we are up. */
		if (!iidev->ready)
			goto done;

		/* It's a command, allocate a message for it. */
		imsg = ipmi_alloc_smi_msg();
		if (!imsg)
			goto done;
		imsg->type = IPMI_SMI_MSG_TYPE_IPMB_DIRECT;
		imsg->data_size = 0;
	} else {
		spin_lock_irqsave(&iidev->lock, flags);
		if (iidev->working_msg) {
			u8 seq = msg[4] >> 2;

Annotation

Implementation Notes