drivers/soc/aspeed/aspeed-lpc-snoop.c
Source file repositories/reference/linux-study-clean/drivers/soc/aspeed/aspeed-lpc-snoop.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/soc/aspeed/aspeed-lpc-snoop.c- Extension
.c- Size
- 10143 bytes
- Lines
- 385
- Domain
- Driver Families
- Bucket
- drivers/soc
- 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.
- 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.
- Defines an operation table; this is where Linux turns generic core objects into subsystem-specific behavior.
- 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/bitops.hlinux/clk.hlinux/dev_printk.hlinux/interrupt.hlinux/fs.hlinux/kfifo.hlinux/mfd/syscon.hlinux/miscdevice.hlinux/module.hlinux/of.hlinux/platform_device.hlinux/poll.hlinux/regmap.h
Detected Declarations
struct aspeed_lpc_snoop_model_datastruct aspeed_lpc_snoop_channel_cfgstruct aspeed_lpc_snoop_channelstruct aspeed_lpc_snoopenum aspeed_lpc_snoop_indexfunction snoop_file_readfunction snoop_file_pollfunction put_fifo_with_discardfunction aspeed_lpc_snoop_irqfunction aspeed_lpc_snoop_config_irqfunction aspeed_lpc_enable_snoopfunction aspeed_lpc_disable_snoopfunction aspeed_lpc_snoop_removefunction aspeed_lpc_snoop_probe
Annotated Snippet
static const struct file_operations snoop_fops = {
.owner = THIS_MODULE,
.read = snoop_file_read,
.poll = snoop_file_poll,
.llseek = noop_llseek,
};
/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
static void put_fifo_with_discard(struct aspeed_lpc_snoop_channel *chan, u8 val)
{
if (!kfifo_initialized(&chan->fifo))
return;
if (kfifo_is_full(&chan->fifo))
kfifo_skip(&chan->fifo);
kfifo_put(&chan->fifo, val);
wake_up_interruptible(&chan->wq);
}
static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg)
{
struct aspeed_lpc_snoop *lpc_snoop = arg;
u32 reg, data;
if (regmap_read(lpc_snoop->regmap, HICR6, ®))
return IRQ_NONE;
/* Check if one of the snoop channels is interrupting */
reg &= (HICR6_STR_SNP0W | HICR6_STR_SNP1W);
if (!reg)
return IRQ_NONE;
/* Ack pending IRQs */
regmap_write(lpc_snoop->regmap, HICR6, reg);
/* Read and save most recent snoop'ed data byte to FIFO */
regmap_read(lpc_snoop->regmap, SNPWDR, &data);
if (reg & HICR6_STR_SNP0W) {
u8 val = (data & SNPWDR_CH0_MASK) >> SNPWDR_CH0_SHIFT;
put_fifo_with_discard(&lpc_snoop->chan[0], val);
}
if (reg & HICR6_STR_SNP1W) {
u8 val = (data & SNPWDR_CH1_MASK) >> SNPWDR_CH1_SHIFT;
put_fifo_with_discard(&lpc_snoop->chan[1], val);
}
return IRQ_HANDLED;
}
static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int rc;
lpc_snoop->irq = platform_get_irq(pdev, 0);
if (lpc_snoop->irq < 0)
return -ENODEV;
rc = devm_request_irq(dev, lpc_snoop->irq,
aspeed_lpc_snoop_irq, IRQF_SHARED,
DEVICE_NAME, lpc_snoop);
if (rc < 0) {
dev_warn(dev, "Unable to request IRQ %d\n", lpc_snoop->irq);
lpc_snoop->irq = 0;
return rc;
}
return 0;
}
__attribute__((nonnull))
static int aspeed_lpc_enable_snoop(struct device *dev,
struct aspeed_lpc_snoop *lpc_snoop,
struct aspeed_lpc_snoop_channel *channel,
const struct aspeed_lpc_snoop_channel_cfg *cfg,
u16 lpc_port)
{
const struct aspeed_lpc_snoop_model_data *model_data;
int rc = 0;
if (WARN_ON(channel->enabled))
return -EBUSY;
init_waitqueue_head(&channel->wq);
channel->cfg = cfg;
channel->miscdev.minor = MISC_DYNAMIC_MINOR;
Annotation
- Immediate include surface: `linux/bitops.h`, `linux/clk.h`, `linux/dev_printk.h`, `linux/interrupt.h`, `linux/fs.h`, `linux/kfifo.h`, `linux/mfd/syscon.h`, `linux/miscdevice.h`.
- Detected declarations: `struct aspeed_lpc_snoop_model_data`, `struct aspeed_lpc_snoop_channel_cfg`, `struct aspeed_lpc_snoop_channel`, `struct aspeed_lpc_snoop`, `enum aspeed_lpc_snoop_index`, `function snoop_file_read`, `function snoop_file_poll`, `function put_fifo_with_discard`, `function aspeed_lpc_snoop_irq`, `function aspeed_lpc_snoop_config_irq`.
- Atlas domain: Driver Families / drivers/soc.
- Implementation status: pattern implementation candidate.
- 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.