Skip to content

Commit b7fbca3

Browse files
RengarajanSSgregkh
authored andcommitted
8250: microchip: pci1xxxx: Add Syslock support for reading UART system registers
Different Host drivers can attempt to access system registers simultaneously from different memory spaces at the same time. The syslock mechanism provides a safe option for reading UART system registers and prevents conflicts by serializing access. Added three padding bytes in the structure for memory alignment. Signed-off-by: Rengarajan S <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e0ae143 commit b7fbca3

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

drivers/tty/serial/8250/8250_pci1xxxx.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,21 @@
99

1010
#include <linux/bitfield.h>
1111
#include <linux/bitops.h>
12+
#include <linux/delay.h>
1213
#include <linux/io.h>
14+
#include <linux/iopoll.h>
1315
#include <linux/kernel.h>
1416
#include <linux/module.h>
1517
#include <linux/pci.h>
1618
#include <linux/serial_core.h>
19+
#include <linux/serial_reg.h>
20+
#include <linux/serial_8250.h>
1721
#include <linux/slab.h>
1822
#include <linux/string.h>
1923
#include <linux/units.h>
2024
#include <linux/tty.h>
25+
#include <linux/tty_flip.h>
26+
#include <linux/8250_pci.h>
2127

2228
#include <asm/byteorder.h>
2329

@@ -52,6 +58,14 @@
5258
#define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400
5359
#define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414
5460

61+
#define UART_SYSTEM_ADDR_BASE 0x1000
62+
#define UART_DEV_REV_REG (UART_SYSTEM_ADDR_BASE + 0x00)
63+
#define UART_DEV_REV_MASK GENMASK(7, 0)
64+
#define UART_SYSLOCK_REG (UART_SYSTEM_ADDR_BASE + 0xA0)
65+
#define UART_SYSLOCK BIT(2)
66+
#define SYSLOCK_SLEEP_TIMEOUT 100
67+
#define SYSLOCK_RETRY_CNT 1000
68+
5569
#define UART_ACTV_REG 0x11
5670
#define UART_BLOCK_SET_ACTIVE BIT(0)
5771

@@ -87,6 +101,8 @@
87101

88102
struct pci1xxxx_8250 {
89103
unsigned int nr;
104+
u8 dev_rev;
105+
u8 pad[3];
90106
void __iomem *membase;
91107
int line[] __counted_by(nr);
92108
};
@@ -98,6 +114,27 @@ static const struct serial_rs485 pci1xxxx_rs485_supported = {
98114
/* Delay RTS before send is not supported */
99115
};
100116

117+
static int pci1xxxx_set_sys_lock(struct pci1xxxx_8250 *port)
118+
{
119+
writel(UART_SYSLOCK, port->membase + UART_SYSLOCK_REG);
120+
return readl(port->membase + UART_SYSLOCK_REG);
121+
}
122+
123+
static int pci1xxxx_acquire_sys_lock(struct pci1xxxx_8250 *port)
124+
{
125+
u32 regval;
126+
127+
return readx_poll_timeout(pci1xxxx_set_sys_lock, port, regval,
128+
(regval & UART_SYSLOCK),
129+
SYSLOCK_SLEEP_TIMEOUT,
130+
SYSLOCK_RETRY_CNT * SYSLOCK_SLEEP_TIMEOUT);
131+
}
132+
133+
static void pci1xxxx_release_sys_lock(struct pci1xxxx_8250 *port)
134+
{
135+
writel(0x0, port->membase + UART_SYSLOCK_REG);
136+
}
137+
101138
static const int logical_to_physical_port_idx[][MAX_PORTS] = {
102139
{0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */
103140
{0, 1, 2, 3}, /* PCI4p */
@@ -370,6 +407,27 @@ static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port)
370407
return logical_to_physical_port_idx[0][port];
371408
}
372409

410+
static int pci1xxxx_get_device_revision(struct pci1xxxx_8250 *priv)
411+
{
412+
u32 regval;
413+
int ret;
414+
415+
/*
416+
* DEV REV is a system register, HW Syslock bit
417+
* should be acquired before accessing the register
418+
*/
419+
ret = pci1xxxx_acquire_sys_lock(priv);
420+
if (ret)
421+
return ret;
422+
423+
regval = readl(priv->membase + UART_DEV_REV_REG);
424+
priv->dev_rev = regval & UART_DEV_REV_MASK;
425+
426+
pci1xxxx_release_sys_lock(priv);
427+
428+
return 0;
429+
}
430+
373431
static int pci1xxxx_serial_probe(struct pci_dev *pdev,
374432
const struct pci_device_id *id)
375433
{
@@ -381,6 +439,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
381439
int num_vectors;
382440
int subsys_dev;
383441
int port_idx;
442+
int ret;
384443
int rc;
385444

386445
rc = pcim_enable_device(pdev);
@@ -397,6 +456,10 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
397456
if (!priv->membase)
398457
return -ENOMEM;
399458

459+
ret = pci1xxxx_get_device_revision(priv);
460+
if (ret)
461+
return ret;
462+
400463
pci_set_master(pdev);
401464

402465
priv->nr = nr_ports;

0 commit comments

Comments
 (0)