How do you patch the 8250_exar driver in RHEL 8 and 9 for Sealevel XR17V35X cards?

This is intended for RHEL 8 and RHEL 9 users impacted by the communication issues described in this support article regarding Sealevel’s XR17V35X-based serial devices (7xxxec serial cards, 7106e, Relio R1).

The steps below describe blocking the original driver, patching the driver, and loading the patched driver. This procedure is required on RHEL due to 8250_exar being built into the kernel rather than as a loadable module.

1. Install packages needed to compile drivers

> yum groupinstall 'Development Tools'

> yum install kernel-devel kernel-headers

2. Edit GRUB_CMDLINE_LINUX in /etc/default/grub to contain

> 8250.nr_uarts=16 initcall_blacklist=exar_pci_driver_init

This will increase the number of supported serial ports to 16 (Use a higher number if you need more) and blacklist the 8250_exar driver used by our XR17V35X cards from loading. We must blacklist the driver to prevent driver conflicts when we load the new driver.

3. Update your grub config.

> sudo grub2-mkconfig -o /boot/grub2/grub.cfg

4. Reboot

5. Download and extract your kernel source from https://mirrors.edge.kernel.org/pub/linux/kernel/
>Tip: You can determine your kernel version by running `cat /proc/version`

>Tip: You may alternatively obtain your source code through your Red Hat Customer Portal login.

6. Navigate to `drivers/tty/serial/8250` in the kernel source.

7. Copy `8250_exar.c` and rename it to `8250_exar_sealevel.c`

> cp 8250_exar.c 8250_exar_sealevel.c

8. Replace the contents of `Makefile` with
```
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the 8250 serial device drivers.
#

obj-m += 8250_exar.o
obj-m += 8250_exar_sealevel.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
```

9. Replace `setup_gpio()` in `8250_exar_sealevel.c` with the content below.
```
static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
{
/*
* The Commtech adapters required the MPIOs to be driven low. The Exar
* devices will export them as GPIOs, so we pre-configure them safely
* as inputs.
*/

u8 dir = 0x00;

if ((pcidev->vendor == PCI_VENDOR_ID_EXAR) &&
(pcidev->subsystem_vendor != PCI_VENDOR_ID_SEALEVEL)) {
// Configure GPIO as inputs for Commtech adapters
dir = 0xff;
} else {
// Configure GPIO as outputs for SeaLevel adapters
dir = 0x00;
}

writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
writeb(dir, p + UART_EXAR_MPIOSEL_7_0);
writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
writeb(dir, p + UART_EXAR_MPIOSEL_15_8);
writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
}
```
> Tip: This is taken from the mainline repository at https://github.com/torvalds/linux/commit/5fdbe136ae19ab751daaa4d08d9a42f3e30d17f9

10. Rename `exar_pci_driver` to match what is shown below. This prevents the new driver from being blacklisted by the changes in step 2.
```
static struct pci_driver exar_sealevel_pci_driver = {
.name = "exar_sealevel_serial",
.probe = exar_pci_probe,
.remove = exar_pci_remove,
.driver = {
.pm = &exar_pci_pm,
},
.id_table = exar_pci_tbl,
};
module_pci_driver(exar_sealevel_pci_driver);
```

11. Save `8250_exar_sealevel.c`

12. Build the driver

>make

13. Load the driver

>insmod 8250_exar_sealevel.ko

14. Verify the driver loaded

>dmesg | grep ttyS

You should see something similar to the message below
```
[ 2757.644239] 0000:01:00.0: ttyS4 at MMIO 0xdfcfc000 (irq = 28, base_baud = 7812500) is a XR17V35X
[ 2757.645930] 0000:01:00.0: ttyS5 at MMIO 0xdfcfc400 (irq = 28, base_baud = 7812500) is a XR17V35X
[ 2757.652420] 0000:01:00.0: ttyS6 at MMIO 0xdfcfc800 (irq = 28, base_baud = 7812500) is a XR17V35X
[ 2757.652841] 0000:01:00.0: ttyS7 at MMIO 0xdfcfcc00 (irq = 28, base_baud = 7812500) is a XR17V35X
```