Implement device-specific RX trigger handling for the rx_trig_bytes sysfs
attribute on MXUPCI parts by programming the vendor registers directly.
Changes:
- Introduce a per-port structure to persist the registered line and the
RX trigger level, so the level can be restored on startup.
- Implement uart_port callbacks:
- set_rxtrig(port, bytes): program MOXA_UART_RBRTI and cache the level
- get_rxtrig(port): return the cached RX trigger level
- Use the cached RX trigger level during startup instead of a fixed
default, while keeping the initial default at 96 for backward
compatibility.
With these callbacks, writes to rx_trig_bytes update the hardware-specific
register and the selected threshold is preserved across open/close cycles.
No functional change for other 8250 drivers.
Signed-off-by: Crescent Hsieh <crescentcy.hsieh@moxa.com>
---
drivers/tty/serial/8250/8250_mxupci.c | 61 ++++++++++++++++++++++++---
1 file changed, 54 insertions(+), 7 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_mxupci.c b/drivers/tty/serial/8250/8250_mxupci.c
index 0eeaf0fa1538..15565729b7e4 100644
--- a/drivers/tty/serial/8250/8250_mxupci.c
+++ b/drivers/tty/serial/8250/8250_mxupci.c
@@ -86,10 +86,15 @@
#define MOXA_UART_RBRTI 0x06 /* Rx Interrupt Trigger Level */
#define MOXA_UART_THRTL 0x07 /* Tx Interrupt Trigger Level */
+struct mxupci8250_port {
+ int line;
+ u8 rx_trig_level;
+};
+
struct mxupci8250 {
struct pci_dev *pdev;
unsigned int num_ports;
- int line[];
+ struct mxupci8250_port port[];
};
static unsigned short mxupci8250_get_nports(unsigned short device)
@@ -150,6 +155,8 @@ static void mxupci8250_set_termios(struct uart_port *port, struct ktermios *new,
static int mxupci8250_startup(struct uart_port *port)
{
+ struct pci_dev *pdev = to_pci_dev(port->dev);
+ struct mxupci8250 *priv = pci_get_drvdata(pdev);
struct uart_8250_port *up = up_to_u8250p(port);
int ret;
u8 efr;
@@ -167,7 +174,7 @@ static int mxupci8250_startup(struct uart_port *port)
serial_out(up, UART_EFR, efr);
serial_out(up, MOXA_UART_THRTL, 0);
- serial_out(up, MOXA_UART_RBRTI, 96);
+ serial_out(up, MOXA_UART_RBRTI, priv->port[port->port_id].rx_trig_level);
serial_out(up, MOXA_UART_RBRTL, 32);
serial_out(up, MOXA_UART_RBRTH, 96);
@@ -309,6 +316,43 @@ static int mxupci8250_handle_irq(struct uart_port *port)
return 1;
}
+static int mxupci8250_set_rxtrig(struct uart_port *port, unsigned char bytes)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct pci_dev *pdev = to_pci_dev(port->dev);
+ struct mxupci8250 *priv = pci_get_drvdata(pdev);
+ u8 efr;
+
+ if (bytes > 128)
+ return -EINVAL;
+
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+ efr = serial_in(up, UART_EFR);
+ efr |= UART_EFR_ECB;
+ serial_out(up, UART_EFR, efr);
+
+ efr &= ~MOXA_UART_EFR_PAGE_MASK;
+ efr |= MOXA_UART_EFR_PAGE_1;
+ serial_out(up, UART_EFR, efr);
+
+ serial_out(up, MOXA_UART_RBRTI, bytes);
+
+ serial_out(up, UART_LCR, up->lcr);
+
+ priv->port[port->port_id].rx_trig_level = bytes;
+
+ return 0;
+}
+
+static int mxupci8250_get_rxtrig(struct uart_port *port)
+{
+ struct pci_dev *pdev = to_pci_dev(port->dev);
+ struct mxupci8250 *priv = pci_get_drvdata(pdev);
+
+ return priv->port[port->port_id].rx_trig_level;
+}
+
static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct uart_8250_port up;
@@ -324,7 +368,7 @@ static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
num_ports = mxupci8250_get_nports(pdev->device);
- priv = devm_kzalloc(&pdev->dev, struct_size(priv, line, num_ports), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, struct_size(priv, port, num_ports), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -346,6 +390,8 @@ static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
up.port.throttle = mxupci8250_throttle;
up.port.unthrottle = mxupci8250_unthrottle;
up.port.handle_irq = mxupci8250_handle_irq;
+ up.port.set_rxtrig = mxupci8250_set_rxtrig;
+ up.port.get_rxtrig = mxupci8250_get_rxtrig;
for (i = 0; i < num_ports; i++) {
if (serial8250_pci_setup_port(pdev, &up, FL_GET_BASE(FL_BASE2), i * MOXA_UART_OFFSET, 0))
@@ -354,15 +400,16 @@ static int mxupci8250_probe(struct pci_dev *pdev, const struct pci_device_id *id
dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
up.port.iobase, up.port.irq, up.port.iotype);
- priv->line[i] = serial8250_register_8250_port(&up);
+ priv->port[i].line = serial8250_register_8250_port(&up);
- if (priv->line[i] < 0) {
+ if (priv->port[i].line < 0) {
dev_err(&pdev->dev,
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
up.port.iobase, up.port.irq,
- up.port.iotype, priv->line[i]);
+ up.port.iotype, priv->port[i].line);
break;
}
+ priv->port[i].rx_trig_level = 96;
}
pci_set_drvdata(pdev, priv);
@@ -375,7 +422,7 @@ static void mxupci8250_remove(struct pci_dev *pdev)
unsigned int i;
for (i = 0; i < priv->num_ports; i++)
- serial8250_unregister_port(priv->line[i]);
+ serial8250_unregister_port(priv->port[i].line);
}
static const struct pci_device_id mxupci8250_pci_ids[] = {
--
2.45.2