How to patch 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 issue described in this support article: https://www.sealevel.com/support/how-to-resolve-communication-issues-affecting-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
```