drivers/char/ipmi/ssif_bmc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/char/ipmi/ssif_bmc.c
Extension
.c
Size
38027 bytes
Lines
1265
Domain
Driver Families
Bucket
drivers/char
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations ssif_bmc_fops = {
	.owner		= THIS_MODULE,
	.open		= ssif_bmc_open,
	.read		= ssif_bmc_read,
	.write		= ssif_bmc_write,
	.release	= ssif_bmc_release,
	.poll		= ssif_bmc_poll,
};

/* Called with ssif_bmc->lock held. */
static void complete_response(struct ssif_bmc_ctx *ssif_bmc)
{
	/* Invalidate response in buffer to denote it having been sent. */
	ssif_bmc->response.len = 0;
	ssif_bmc->response_in_progress = false;
	ssif_bmc->nbytes_processed = 0;
	ssif_bmc->remain_len = 0;
	ssif_bmc->busy = false;
	wake_up_all(&ssif_bmc->wait_queue);
}

static void response_timeout(struct timer_list *t)
{
	struct ssif_bmc_ctx *ssif_bmc = timer_container_of(ssif_bmc, t,
							   response_timer);
	unsigned long flags;

	spin_lock_irqsave(&ssif_bmc->lock, flags);

	/* Do nothing if the response is in progress */
	if (!ssif_bmc->response_in_progress) {
		/* Recover ssif_bmc from busy */
		ssif_bmc->busy = false;
		ssif_bmc->response_timer_inited = false;
		/* Set aborting flag */
		ssif_bmc->aborting = true;
	}

	spin_unlock_irqrestore(&ssif_bmc->lock, flags);
}

/* Called with ssif_bmc->lock held. */
static void handle_request(struct ssif_bmc_ctx *ssif_bmc)
{
	/* set ssif_bmc to busy waiting for response */
	ssif_bmc->busy = true;
	/* Request message is available to process */
	ssif_bmc->request_available = true;
	/* Clean old response buffer */
	memset(&ssif_bmc->response, 0, sizeof(struct ipmi_ssif_msg));
	/* This is the new READ request.*/
	wake_up_all(&ssif_bmc->wait_queue);

	/* Armed timer to recover slave from busy state in case of no response */
	if (!ssif_bmc->response_timer_inited) {
		timer_setup(&ssif_bmc->response_timer, response_timeout, 0);
		ssif_bmc->response_timer_inited = true;
	}
	mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT));
}

static void calculate_response_part_pec(struct ssif_part_buffer *part)
{
	u8 addr = part->address;

	/* PEC - Start Read Address */
	part->pec = i2c_smbus_pec(0, &addr, 1);
	/* PEC - SSIF Command */
	part->pec = i2c_smbus_pec(part->pec, &part->smbus_cmd, 1);
	/* PEC - Restart Write Address */
	addr = addr | 0x01;
	part->pec = i2c_smbus_pec(part->pec, &addr, 1);
	part->pec = i2c_smbus_pec(part->pec, &part->length, 1);
	if (part->length)
		part->pec = i2c_smbus_pec(part->pec, part->payload, part->length);
}

static void set_singlepart_response_buffer(struct ssif_bmc_ctx *ssif_bmc)
{
	struct ssif_part_buffer *part = &ssif_bmc->part_buf;

	part->address = GET_8BIT_ADDR(ssif_bmc->client->addr);
	part->length = (u8)ssif_bmc->response.len;

	/* Clear the rest to 0 */
	memset(part->payload + part->length, 0, MAX_PAYLOAD_PER_TRANSACTION - part->length);
	memcpy(&part->payload[0], &ssif_bmc->response.payload[0], part->length);
}

static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc)

Annotation

Implementation Notes