1616
1717#include <linux/bitops.h>
1818#include <linux/interrupt.h>
19+ #include <linux/fs.h>
1920#include <linux/kfifo.h>
2021#include <linux/mfd/syscon.h>
22+ #include <linux/miscdevice.h>
2123#include <linux/module.h>
2224#include <linux/of.h>
2325#include <linux/of_device.h>
2426#include <linux/platform_device.h>
27+ #include <linux/poll.h>
2528#include <linux/regmap.h>
2629
2730#define DEVICE_NAME "aspeed-lpc-snoop"
@@ -59,20 +62,70 @@ struct aspeed_lpc_snoop_model_data {
5962 unsigned int has_hicrb_ensnp ;
6063};
6164
65+ struct aspeed_lpc_snoop_channel {
66+ struct kfifo fifo ;
67+ wait_queue_head_t wq ;
68+ struct miscdevice miscdev ;
69+ };
70+
6271struct aspeed_lpc_snoop {
6372 struct regmap * regmap ;
6473 int irq ;
65- struct kfifo snoop_fifo [NUM_SNOOP_CHANNELS ];
74+ struct aspeed_lpc_snoop_channel chan [NUM_SNOOP_CHANNELS ];
75+ };
76+
77+ static struct aspeed_lpc_snoop_channel * snoop_file_to_chan (struct file * file )
78+ {
79+ return container_of (file -> private_data ,
80+ struct aspeed_lpc_snoop_channel ,
81+ miscdev );
82+ }
83+
84+ static ssize_t snoop_file_read (struct file * file , char __user * buffer ,
85+ size_t count , loff_t * ppos )
86+ {
87+ struct aspeed_lpc_snoop_channel * chan = snoop_file_to_chan (file );
88+ unsigned int copied ;
89+ int ret = 0 ;
90+
91+ if (kfifo_is_empty (& chan -> fifo )) {
92+ if (file -> f_flags & O_NONBLOCK )
93+ return - EAGAIN ;
94+ ret = wait_event_interruptible (chan -> wq ,
95+ !kfifo_is_empty (& chan -> fifo ));
96+ if (ret == - ERESTARTSYS )
97+ return - EINTR ;
98+ }
99+ ret = kfifo_to_user (& chan -> fifo , buffer , count , & copied );
100+
101+ return ret ? ret : copied ;
102+ }
103+
104+ static unsigned int snoop_file_poll (struct file * file ,
105+ struct poll_table_struct * pt )
106+ {
107+ struct aspeed_lpc_snoop_channel * chan = snoop_file_to_chan (file );
108+
109+ poll_wait (file , & chan -> wq , pt );
110+ return !kfifo_is_empty (& chan -> fifo ) ? POLLIN : 0 ;
111+ }
112+
113+ static const struct file_operations snoop_fops = {
114+ .owner = THIS_MODULE ,
115+ .read = snoop_file_read ,
116+ .poll = snoop_file_poll ,
117+ .llseek = noop_llseek ,
66118};
67119
68120/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */
69- static void put_fifo_with_discard (struct kfifo * fifo , u8 val )
121+ static void put_fifo_with_discard (struct aspeed_lpc_snoop_channel * chan , u8 val )
70122{
71- if (!kfifo_initialized (fifo ))
123+ if (!kfifo_initialized (& chan -> fifo ))
72124 return ;
73- if (kfifo_is_full (fifo ))
74- kfifo_skip (fifo );
75- kfifo_put (fifo , val );
125+ if (kfifo_is_full (& chan -> fifo ))
126+ kfifo_skip (& chan -> fifo );
127+ kfifo_put (& chan -> fifo , val );
128+ wake_up_interruptible (& chan -> wq );
76129}
77130
78131static irqreturn_t aspeed_lpc_snoop_irq (int irq , void * arg )
@@ -97,12 +150,12 @@ static irqreturn_t aspeed_lpc_snoop_irq(int irq, void *arg)
97150 if (reg & HICR6_STR_SNP0W ) {
98151 u8 val = (data & SNPWDR_CH0_MASK ) >> SNPWDR_CH0_SHIFT ;
99152
100- put_fifo_with_discard (& lpc_snoop -> snoop_fifo [0 ], val );
153+ put_fifo_with_discard (& lpc_snoop -> chan [0 ], val );
101154 }
102155 if (reg & HICR6_STR_SNP1W ) {
103156 u8 val = (data & SNPWDR_CH1_MASK ) >> SNPWDR_CH1_SHIFT ;
104157
105- put_fifo_with_discard (& lpc_snoop -> snoop_fifo [1 ], val );
158+ put_fifo_with_discard (& lpc_snoop -> chan [1 ], val );
106159 }
107160
108161 return IRQ_HANDLED ;
@@ -139,12 +192,22 @@ static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
139192 const struct aspeed_lpc_snoop_model_data * model_data =
140193 of_device_get_match_data (dev );
141194
195+ init_waitqueue_head (& lpc_snoop -> chan [channel ].wq );
142196 /* Create FIFO datastructure */
143- rc = kfifo_alloc (& lpc_snoop -> snoop_fifo [channel ],
197+ rc = kfifo_alloc (& lpc_snoop -> chan [channel ]. fifo ,
144198 SNOOP_FIFO_SIZE , GFP_KERNEL );
145199 if (rc )
146200 return rc ;
147201
202+ lpc_snoop -> chan [channel ].miscdev .minor = MISC_DYNAMIC_MINOR ;
203+ lpc_snoop -> chan [channel ].miscdev .name =
204+ devm_kasprintf (dev , GFP_KERNEL , "%s%d" , DEVICE_NAME , channel );
205+ lpc_snoop -> chan [channel ].miscdev .fops = & snoop_fops ;
206+ lpc_snoop -> chan [channel ].miscdev .parent = dev ;
207+ rc = misc_register (& lpc_snoop -> chan [channel ].miscdev );
208+ if (rc )
209+ return rc ;
210+
148211 /* Enable LPC snoop channel at requested port */
149212 switch (channel ) {
150213 case 0 :
@@ -191,7 +254,8 @@ static void aspeed_lpc_disable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
191254 return ;
192255 }
193256
194- kfifo_free (& lpc_snoop -> snoop_fifo [channel ]);
257+ kfifo_free (& lpc_snoop -> chan [channel ].fifo );
258+ misc_deregister (& lpc_snoop -> chan [channel ].miscdev );
195259}
196260
197261static int aspeed_lpc_snoop_probe (struct platform_device * pdev )
0 commit comments