[PATCH] aspeed-lpc-snoop: add 16-bit POST code support
From: Joel Stanley <joel@jms.id.au>
Date: 2021-11-17 04:10:00
Also in:
linux-arm-kernel, lkml
Hi Govert, On Wed, 24 Feb 2021 at 09:07, Govert Overgaauw [off-list ref] wrote:
Intel coffeelake plattform uses a 16-bit POST code format instead of 8-bit. Add a third FIFO for storing the combined 16-bit post codes.
Thanks for the patch. It slipped through the cracks. I would like to merge it if we could get some review and/or testing. Ryan, Zev, Oskar, Lei: please jump in if you're able to help. Cheers, Joel
quoted hunk
Signed-off-by: Govert Overgaauw <redacted> --- drivers/soc/aspeed/aspeed-lpc-snoop.c | 117 +++++++++++++++++--------- 1 file changed, 79 insertions(+), 38 deletions(-)diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index 682ba0eb4eba..40d113d253fc 100644 --- a/drivers/soc/aspeed/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c@@ -58,7 +58,7 @@ struct aspeed_lpc_snoop_model_data { unsigned int has_hicrb_ensnp; }; -struct aspeed_lpc_snoop_channel { +struct aspeed_lpc_snoop_fifo { struct kfifo fifo; wait_queue_head_t wq; struct miscdevice miscdev;@@ -67,32 +67,39 @@ struct aspeed_lpc_snoop_channel { struct aspeed_lpc_snoop { struct regmap *regmap; int irq; - struct aspeed_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS]; + struct aspeed_lpc_snoop_fifo chan[NUM_SNOOP_CHANNELS]; + + /* + * 16-bit postcodes are combination + * of both channels written to a seperate device file, because + * both bytes have to be added on the same interrupt. + */ + struct aspeed_lpc_snoop_fifo combined; }; -static struct aspeed_lpc_snoop_channel *snoop_file_to_chan(struct file *file) +static struct aspeed_lpc_snoop_fifo *snoop_file_to_fifo(struct file *file) { return container_of(file->private_data, - struct aspeed_lpc_snoop_channel, + struct aspeed_lpc_snoop_fifo, miscdev); } static ssize_t snoop_file_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file); + struct aspeed_lpc_snoop_fifo *fifo = snoop_file_to_fifo(file); unsigned int copied; int ret = 0; - if (kfifo_is_empty(&chan->fifo)) { + if (kfifo_is_empty(&fifo->fifo)) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; - ret = wait_event_interruptible(chan->wq, - !kfifo_is_empty(&chan->fifo)); + ret = wait_event_interruptible(fifo->wq, + !kfifo_is_empty(&fifo->fifo)); if (ret == -ERESTARTSYS) return -EINTR; } - ret = kfifo_to_user(&chan->fifo, buffer, count, &copied); + ret = kfifo_to_user(&fifo->fifo, buffer, count, &copied); return ret ? ret : copied; }@@ -100,10 +107,10 @@ static ssize_t snoop_file_read(struct file *file, char __user *buffer, static __poll_t snoop_file_poll(struct file *file, struct poll_table_struct *pt) { - struct aspeed_lpc_snoop_channel *chan = snoop_file_to_chan(file); + struct aspeed_lpc_snoop_fifo *fifo = snoop_file_to_fifo(file); - poll_wait(file, &chan->wq, pt); - return !kfifo_is_empty(&chan->fifo) ? EPOLLIN : 0; + poll_wait(file, &fifo->wq, pt); + return !kfifo_is_empty(&fifo->fifo) ? EPOLLIN : 0; } static const struct file_operations snoop_fops = {@@ -113,21 +120,22 @@ static const struct file_operations snoop_fops = { .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) +/* Save data to a FIFO and discard the oldest byte if FIFO is full */ +static void put_fifo_with_discard(struct aspeed_lpc_snoop_fifo *fifo, size_t len, u8 *buf) { - if (!kfifo_initialized(&chan->fifo)) + if (!kfifo_initialized(&fifo->fifo)) return; - if (kfifo_is_full(&chan->fifo)) - kfifo_skip(&chan->fifo); - kfifo_put(&chan->fifo, val); - wake_up_interruptible(&chan->wq); + if (kfifo_is_full(&fifo->fifo)) + kfifo_skip(&fifo->fifo); + kfifo_in(&fifo->fifo, buf, len); + wake_up_interruptible(&fifo->wq); } static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg) { struct aspeed_lpc_snoop *lpc_snoop = arg; u32 reg, data; + u16 postval = 0; if (regmap_read(lpc_snoop->regmap, HICR6, ®)) return IRQ_NONE;@@ -140,20 +148,25 @@ static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg) /* Ack pending IRQs */ regmap_write(lpc_snoop->regmap, HICR6, reg); - /* Read and save most recent snoop'ed data byte to FIFO */ + /* Read and save most recent snoop'ed data byte(s) 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); + put_fifo_with_discard(&lpc_snoop->chan[0], sizeof(val), &val); + postval |= val; } if (reg & HICR6_STR_SNP1W) { u8 val = (data & SNPWDR_CH1_MASK) >> SNPWDR_CH1_SHIFT; - put_fifo_with_discard(&lpc_snoop->chan[1], val); + put_fifo_with_discard(&lpc_snoop->chan[1], sizeof(val), &val); + postval |= (val << 8); } + if (postval) + put_fifo_with_discard(&lpc_snoop->combined, sizeof(postval), (u8 *)&postval); + return IRQ_HANDLED; }@@ -179,6 +192,34 @@ static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop, return 0; } +static int aspeed_lpc_create_fifo_chardev(struct aspeed_lpc_snoop_fifo *fifo, + struct device *dev, int devnum) +{ + int rc = 0; + + init_waitqueue_head(&fifo->wq); + /* Create FIFO datastructure */ + rc = kfifo_alloc(&fifo->fifo, + SNOOP_FIFO_SIZE, GFP_KERNEL); + if (rc) + return rc; + + fifo->miscdev.minor = MISC_DYNAMIC_MINOR; + fifo->miscdev.name = + devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, devnum); + fifo->miscdev.fops = &snoop_fops; + fifo->miscdev.parent = dev; + + return misc_register(&fifo->miscdev); +} + +static void aspeed_lpc_destroy_fifo_chardev(struct aspeed_lpc_snoop_fifo *fifo) +{ + + kfifo_free(&fifo->fifo); + misc_deregister(&fifo->miscdev); +} + static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, struct device *dev, int channel, u16 lpc_port)@@ -188,19 +229,8 @@ static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, const struct aspeed_lpc_snoop_model_data *model_data = of_device_get_match_data(dev); - init_waitqueue_head(&lpc_snoop->chan[channel].wq); - /* Create FIFO datastructure */ - rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo, - SNOOP_FIFO_SIZE, GFP_KERNEL); - if (rc) - return rc; - - lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR; - lpc_snoop->chan[channel].miscdev.name = - devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel); - lpc_snoop->chan[channel].miscdev.fops = &snoop_fops; - lpc_snoop->chan[channel].miscdev.parent = dev; - rc = misc_register(&lpc_snoop->chan[channel].miscdev); + rc = aspeed_lpc_create_fifo_chardev(&lpc_snoop->chan[channel], + dev, channel); if (rc) return rc;@@ -250,8 +280,7 @@ static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop, return; } - kfifo_free(&lpc_snoop->chan[channel].fifo); - misc_deregister(&lpc_snoop->chan[channel].miscdev); + aspeed_lpc_destroy_fifo_chardev(&lpc_snoop->chan[channel]); } static int aspeed_lpc_snoop_probe(struct platform_device *pdev)@@ -295,9 +324,18 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev) 1, &port) == 0) { rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port); if (rc) - aspeed_lpc_disable_snoop(lpc_snoop, 0); + goto err_port1; + + rc = aspeed_lpc_create_fifo_chardev(&lpc_snoop->combined, dev, 2); + if (rc) + goto err_combined; } + return rc; +err_combined: + aspeed_lpc_disable_snoop(lpc_snoop, 1); +err_port1: + aspeed_lpc_disable_snoop(lpc_snoop, 0); return rc; }@@ -309,6 +347,9 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev) aspeed_lpc_disable_snoop(lpc_snoop, 0); aspeed_lpc_disable_snoop(lpc_snoop, 1); + /* disable combined fifo device */ + aspeed_lpc_destroy_fifo_chardev(&lpc_snoop->combined); + return 0; } --2.20.1