10
10
#include <linux/of_address.h>
11
11
#include <linux/of_irq.h>
12
12
#include <linux/of_platform.h>
13
+ #include <linux/tty.h>
14
+ #include <linux/tty_flip.h>
13
15
#include <linux/clk.h>
14
16
15
17
#include "8250.h"
@@ -28,8 +30,17 @@ struct aspeed_vuart {
28
30
void __iomem * regs ;
29
31
struct clk * clk ;
30
32
int line ;
33
+ struct timer_list unthrottle_timer ;
34
+ struct uart_8250_port * port ;
31
35
};
32
36
37
+ /*
38
+ * If we fill the tty flip buffers, we throttle the data ready interrupt
39
+ * to prevent dropped characters. This timeout defines how long we wait
40
+ * to (conditionally, depending on buffer state) unthrottle.
41
+ */
42
+ static const int unthrottle_timeout = HZ /10 ;
43
+
33
44
/*
34
45
* The VUART is basically two UART 'front ends' connected by their FIFO
35
46
* (no actual serial line in between). One is on the BMC side (management
@@ -179,17 +190,23 @@ static void aspeed_vuart_shutdown(struct uart_port *uart_port)
179
190
serial8250_do_shutdown (uart_port );
180
191
}
181
192
182
- static void aspeed_vuart_set_throttle (struct uart_port * port , bool throttle )
193
+ static void __aspeed_vuart_set_throttle (struct uart_8250_port * up ,
194
+ bool throttle )
183
195
{
184
196
unsigned char irqs = UART_IER_RLSI | UART_IER_RDI ;
185
- struct uart_8250_port * up = up_to_u8250p (port );
186
- unsigned long flags ;
187
197
188
- spin_lock_irqsave (& port -> lock , flags );
189
198
up -> ier &= ~irqs ;
190
199
if (!throttle )
191
200
up -> ier |= irqs ;
192
201
serial_out (up , UART_IER , up -> ier );
202
+ }
203
+ static void aspeed_vuart_set_throttle (struct uart_port * port , bool throttle )
204
+ {
205
+ struct uart_8250_port * up = up_to_u8250p (port );
206
+ unsigned long flags ;
207
+
208
+ spin_lock_irqsave (& port -> lock , flags );
209
+ __aspeed_vuart_set_throttle (up , throttle );
193
210
spin_unlock_irqrestore (& port -> lock , flags );
194
211
}
195
212
@@ -203,6 +220,83 @@ static void aspeed_vuart_unthrottle(struct uart_port *port)
203
220
aspeed_vuart_set_throttle (port , false);
204
221
}
205
222
223
+ static void aspeed_vuart_unthrottle_exp (struct timer_list * timer )
224
+ {
225
+ struct aspeed_vuart * vuart = from_timer (vuart , timer , unthrottle_timer );
226
+ struct uart_8250_port * up = vuart -> port ;
227
+
228
+ if (!tty_buffer_space_avail (& up -> port .state -> port )) {
229
+ mod_timer (& vuart -> unthrottle_timer , unthrottle_timeout );
230
+ return ;
231
+ }
232
+
233
+ aspeed_vuart_unthrottle (& up -> port );
234
+ }
235
+
236
+ /*
237
+ * Custom interrupt handler to manage finer-grained flow control. Although we
238
+ * have throttle/unthrottle callbacks, we've seen that the VUART device can
239
+ * deliver characters faster than the ldisc has a chance to check buffer space
240
+ * against the throttle threshold. This results in dropped characters before
241
+ * the throttle.
242
+ *
243
+ * We do this by checking for flip buffer space before RX. If we have no space,
244
+ * throttle now and schedule an unthrottle for later, once the ldisc has had
245
+ * a chance to drain the buffers.
246
+ */
247
+ static int aspeed_vuart_handle_irq (struct uart_port * port )
248
+ {
249
+ struct uart_8250_port * up = up_to_u8250p (port );
250
+ unsigned int iir , lsr ;
251
+ unsigned long flags ;
252
+ int space , count ;
253
+
254
+ iir = serial_port_in (port , UART_IIR );
255
+
256
+ if (iir & UART_IIR_NO_INT )
257
+ return 0 ;
258
+
259
+ spin_lock_irqsave (& port -> lock , flags );
260
+
261
+ lsr = serial_port_in (port , UART_LSR );
262
+
263
+ if (lsr & (UART_LSR_DR | UART_LSR_BI )) {
264
+ space = tty_buffer_space_avail (& port -> state -> port );
265
+
266
+ if (!space ) {
267
+ /* throttle and schedule an unthrottle later */
268
+ struct aspeed_vuart * vuart = port -> private_data ;
269
+ __aspeed_vuart_set_throttle (up , true);
270
+
271
+ if (!timer_pending (& vuart -> unthrottle_timer )) {
272
+ vuart -> port = up ;
273
+ mod_timer (& vuart -> unthrottle_timer ,
274
+ unthrottle_timeout );
275
+ }
276
+
277
+ } else {
278
+ count = min (space , 256 );
279
+
280
+ do {
281
+ serial8250_read_char (up , lsr );
282
+ lsr = serial_in (up , UART_LSR );
283
+ if (-- count == 0 )
284
+ break ;
285
+ } while (lsr & (UART_LSR_DR | UART_LSR_BI ));
286
+
287
+ tty_flip_buffer_push (& port -> state -> port );
288
+ }
289
+ }
290
+
291
+ serial8250_modem_status (up );
292
+ if (lsr & UART_LSR_THRE )
293
+ serial8250_tx_chars (up );
294
+
295
+ spin_unlock_irqrestore (& port -> lock , flags );
296
+
297
+ return 1 ;
298
+ }
299
+
206
300
static int aspeed_vuart_probe (struct platform_device * pdev )
207
301
{
208
302
struct uart_8250_port port ;
@@ -219,6 +313,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
219
313
return - ENOMEM ;
220
314
221
315
vuart -> dev = & pdev -> dev ;
316
+ timer_setup (& vuart -> unthrottle_timer , aspeed_vuart_unthrottle_exp , 0 );
222
317
223
318
res = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
224
319
vuart -> regs = devm_ioremap_resource (& pdev -> dev , res );
@@ -280,6 +375,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev)
280
375
281
376
port .port .irq = irq_of_parse_and_map (np , 0 );
282
377
port .port .irqflags = IRQF_SHARED ;
378
+ port .port .handle_irq = aspeed_vuart_handle_irq ;
283
379
port .port .iotype = UPIO_MEM ;
284
380
port .port .type = PORT_16550A ;
285
381
port .port .uartclk = clk ;
@@ -319,6 +415,7 @@ static int aspeed_vuart_remove(struct platform_device *pdev)
319
415
{
320
416
struct aspeed_vuart * vuart = platform_get_drvdata (pdev );
321
417
418
+ del_timer_sync (& vuart -> unthrottle_timer );
322
419
aspeed_vuart_set_enabled (vuart , false);
323
420
serial8250_unregister_port (vuart -> line );
324
421
sysfs_remove_group (& vuart -> dev -> kobj , & aspeed_vuart_attr_group );
0 commit comments