/* * If we fill the tty flip buffers, we throttle the data ready interrupt * to prevent dropped characters. This timeout defines how long we wait * to (conditionally, depending on buffer state) unthrottle.
*/ staticconstint unthrottle_timeout = HZ/10;
/* * The VUART is basically two UART 'front ends' connected by their FIFO * (no actual serial line in between). One is on the BMC side (management * controller) and one is on the host CPU side. * * It allows the BMC to provide to the host a "UART" that pipes into * the BMC itself and can then be turned by the BMC into a network console * of some sort for example. * * This driver is for the BMC side. The sysfs files allow the BMC * userspace which owns the system configuration policy, to specify * at what IO port and interrupt number the host side will appear * to the host on the Host <-> BMC LPC bus. It could be different on a * different system (though most of them use 3f8/4).
*/
/* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */ if (!discard)
reg |= ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD; else
reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
if (!tty_buffer_space_avail(&up->port.state->port)) {
mod_timer(&vuart->unthrottle_timer,
jiffies + unthrottle_timeout); return;
}
aspeed_vuart_unthrottle(&up->port);
}
/* * Custom interrupt handler to manage finer-grained flow control. Although we * have throttle/unthrottle callbacks, we've seen that the VUART device can * deliver characters faster than the ldisc has a chance to check buffer space * against the throttle threshold. This results in dropped characters before * the throttle. * * We do this by checking for flip buffer space before RX. If we have no space, * throttle now and schedule an unthrottle for later, once the ldisc has had * a chance to drain the buffers.
*/ staticint aspeed_vuart_handle_irq(struct uart_port *port)
{ struct uart_8250_port *up = up_to_u8250p(port); unsignedint iir, lsr; unsignedlong flags; unsignedint space, count;
iir = serial_port_in(port, UART_IIR);
if (iir & UART_IIR_NO_INT) return 0;
uart_port_lock_irqsave(port, &flags);
lsr = serial_port_in(port, UART_LSR);
if (lsr & (UART_LSR_DR | UART_LSR_BI)) {
space = tty_buffer_space_avail(&port->state->port);
if (!space) { /* throttle and schedule an unthrottle later */ struct aspeed_vuart *vuart = port->private_data;
__aspeed_vuart_set_throttle(up, true);
if (!timer_pending(&vuart->unthrottle_timer))
mod_timer(&vuart->unthrottle_timer,
jiffies + unthrottle_timeout);
} else {
count = min(space, 256U);
do {
serial8250_read_char(up, lsr);
lsr = serial_in(up, UART_LSR); if (--count == 0) break;
} while (lsr & (UART_LSR_DR | UART_LSR_BI));
tty_flip_buffer_push(&port->state->port);
}
}
serial8250_modem_status(up); if (lsr & UART_LSR_THRE)
serial8250_tx_chars(up);
regmap = syscon_node_to_regmap(syscon_np); if (IS_ERR(regmap)) {
dev_warn(vuart->dev, "could not get regmap for aspeed,sirq-polarity-sense\n"); return;
} if (regmap_read(regmap, reg_offset, &value)) {
dev_warn(vuart->dev, "could not read hw strap table\n"); return;
}
rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); if (rc < 0) return rc;
rc = uart_read_port_properties(&port.port); if (rc) goto err_sysfs_remove;
/* Get clk rate through clk driver if present */ if (!port.port.uartclk) {
vclk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(vclk)) {
rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n"); goto err_sysfs_remove;
}
port.port.uartclk = clk_get_rate(vclk);
}
/* If current-speed was set, then try not to change it. */ if (of_property_read_u32(np, "current-speed", &prop) == 0)
port.port.custom_divisor = port.port.uartclk / (16 * prop);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.