drivers/mfd/loongson-se.c
Source file repositories/reference/linux-study-clean/drivers/mfd/loongson-se.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/mfd/loongson-se.c- Extension
.c- Size
- 6531 bytes
- Lines
- 254
- Domain
- Driver Families
- Bucket
- drivers/mfd
- Inferred role
- Driver Families: exported/initcall integration point
- Status
- integration 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.
- 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.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/acpi.hlinux/delay.hlinux/device.hlinux/dma-mapping.hlinux/errno.hlinux/init.hlinux/interrupt.hlinux/iopoll.hlinux/kernel.hlinux/mfd/core.hlinux/mfd/loongson-se.hlinux/module.hlinux/platform_device.h
Detected Declarations
struct loongson_sestruct loongson_se_controller_cmdfunction loongson_se_pollfunction loongson_se_send_controller_cmdfunction loongson_se_send_engine_cmdfunction se_irq_handlerfunction loongson_se_initfunction loongson_se_probeexport loongson_se_send_engine_cmdexport loongson_se_init_engine
Annotated Snippet
struct loongson_se {
void __iomem *base;
spinlock_t dev_lock;
struct completion cmd_completion;
void *dmam_base;
int dmam_size;
struct mutex engine_init_lock;
struct loongson_se_engine engines[SE_ENGINE_MAX];
};
struct loongson_se_controller_cmd {
u32 command_id;
u32 info[7];
};
static int loongson_se_poll(struct loongson_se *se, u32 int_bit)
{
u32 status;
int err;
spin_lock_irq(&se->dev_lock);
/* Notify the controller that the engine needs to be started */
writel(int_bit, se->base + SE_L2SINT_SET);
/* Polling until the controller has forwarded the engine command */
err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status,
!(status & int_bit),
1, LOONGSON_ENGINE_CMD_TIMEOUT_US);
spin_unlock_irq(&se->dev_lock);
return err;
}
static int loongson_se_send_controller_cmd(struct loongson_se *se,
struct loongson_se_controller_cmd *cmd)
{
u32 *send_cmd = (u32 *)cmd;
int err, i;
for (i = 0; i < SE_SEND_CMD_REG_LEN; i++)
writel(send_cmd[i], se->base + SE_SEND_CMD_REG + i * 4);
err = loongson_se_poll(se, SE_INT_CONTROLLER);
if (err)
return err;
return wait_for_completion_interruptible(&se->cmd_completion);
}
int loongson_se_send_engine_cmd(struct loongson_se_engine *engine)
{
/*
* After engine initialization, the controller already knows
* where to obtain engine commands from. Now all we need to
* do is notify the controller that the engine needs to be started.
*/
int err = loongson_se_poll(engine->se, BIT(engine->id));
if (err)
return err;
return wait_for_completion_interruptible(&engine->completion);
}
EXPORT_SYMBOL_GPL(loongson_se_send_engine_cmd);
struct loongson_se_engine *loongson_se_init_engine(struct device *dev, int id)
{
struct loongson_se *se = dev_get_drvdata(dev);
struct loongson_se_engine *engine = &se->engines[id];
struct loongson_se_controller_cmd cmd;
engine->se = se;
engine->id = id;
init_completion(&engine->completion);
/* Divide DMA memory equally among all engines */
engine->buffer_size = se->dmam_size / SE_ENGINE_MAX;
engine->buffer_off = (se->dmam_size / SE_ENGINE_MAX) * id;
engine->data_buffer = se->dmam_base + engine->buffer_off;
/*
* There has no engine0, use its data buffer as command buffer for other
* engines. The DMA memory size is obtained from the ACPI table, which
* ensures that the data buffer size of engine0 is larger than the
* command buffer size of all engines.
*/
Annotation
- Immediate include surface: `linux/acpi.h`, `linux/delay.h`, `linux/device.h`, `linux/dma-mapping.h`, `linux/errno.h`, `linux/init.h`, `linux/interrupt.h`, `linux/iopoll.h`.
- Detected declarations: `struct loongson_se`, `struct loongson_se_controller_cmd`, `function loongson_se_poll`, `function loongson_se_send_controller_cmd`, `function loongson_se_send_engine_cmd`, `function se_irq_handler`, `function loongson_se_init`, `function loongson_se_probe`, `export loongson_se_send_engine_cmd`, `export loongson_se_init_engine`.
- Atlas domain: Driver Families / drivers/mfd.
- Implementation status: integration implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.