--- v9
+++ v12
@@ -10,27 +10,29 @@
Serial portion: Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
+Network part: Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
+Network part: Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
- arch/mips/sgi-ip27/ip27-timer.c | 20 --
+ arch/mips/sgi-ip27/ip27-timer.c | 20 -
drivers/mfd/Kconfig | 13 +
drivers/mfd/Makefile | 1 +
- drivers/mfd/ioc3.c | 605 ++++++++++++++++++++++++++++++++++++
+ drivers/mfd/ioc3.c | 669 ++++++++++++++++++++++++++++
drivers/net/ethernet/sgi/Kconfig | 5 +-
- drivers/net/ethernet/sgi/ioc3-eth.c | 561 ++++++---------------------------
- drivers/tty/serial/8250/8250_ioc3.c | 98 ++++++
+ drivers/net/ethernet/sgi/ioc3-eth.c | 556 ++++-------------------
+ drivers/tty/serial/8250/8250_ioc3.c | 98 ++++
drivers/tty/serial/8250/Kconfig | 11 +
drivers/tty/serial/8250/Makefile | 1 +
- 9 files changed, 830 insertions(+), 485 deletions(-)
+ 9 files changed, 893 insertions(+), 481 deletions(-)
create mode 100644 drivers/mfd/ioc3.c
create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
-index 9b4b9ac621a3..5631e93ea350 100644
+index 17302bbfa7a6..d53a29070e12 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
-@@ -188,23 +188,3 @@ void hub_rtc_init(cnodeid_t cnode)
+@@ -190,23 +190,3 @@ void hub_rtc_init(nasid_t nasid)
LOCAL_HUB_S(PI_RT_PEND_B, 0);
}
}
@@ -55,10 +57,10 @@
- */
-late_initcall(sgi_ip27_rtc_devinit);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
-index ae24d3ea68ea..a762342065a2 100644
+index 420900852166..7a4a41dddc97 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
-@@ -2011,5 +2011,18 @@ config RAVE_SP_CORE
+@@ -2004,5 +2004,18 @@ config RAVE_SP_CORE
Select this to get support for the Supervisory Processor
device found on several devices in RAVE line of hardware.
@@ -78,20 +80,20 @@
endmenu
endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
-index c1067ea46204..0d89b9e1055f 100644
+index aed99f08739f..5fe930c76ade 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
-@@ -256,3 +256,4 @@ obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
+@@ -255,3 +255,4 @@ obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
+obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
diff --git a/drivers/mfd/ioc3.c b/drivers/mfd/ioc3.c
new file mode 100644
-index 000000000000..4b0bd124fc13
+index 000000000000..02998d4eb74b
--- /dev/null
+++ b/drivers/mfd/ioc3.c
-@@ -0,0 +1,605 @@
+@@ -0,0 +1,669 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SGI IOC3 multifunction device driver
@@ -113,6 +115,7 @@
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/sgi-w1.h>
++#include <linux/rtc/ds1685.h>
+
+#include <asm/pci/bridge.h>
+#include <asm/sn/ioc3.h>
@@ -120,7 +123,6 @@
+#define IOC3_IRQ_SERIAL_A 6
+#define IOC3_IRQ_SERIAL_B 15
+#define IOC3_IRQ_KBD 22
-+#define IOC3_IRQ_ETH_DOMAIN 23
+
+/* Bitmask for selecting which IRQs are level triggered */
+#define IOC3_LVL_MASK (BIT(IOC3_IRQ_SERIAL_A) | BIT(IOC3_IRQ_SERIAL_B))
@@ -203,14 +205,6 @@
+ pending = readl(®s->sio_ir);
+ mask = readl(®s->sio_ies);
+ pending &= mask; /* Mask off not enabled interrupts */
-+
-+ if (mask & BIT(IOC3_IRQ_ETH_DOMAIN))
-+ /*
-+ * If ethernet interrupt is enabled we need to check
-+ * ethernet registers for pending interrupts
-+ */
-+ if (readl(®s->eth.eisr) & readl(®s->eth.eier))
-+ pending |= IOC3_IRQ_ETH_DOMAIN;
+
+ if (pending) {
+ irq = irq_find_mapping(domain, __ffs(pending));
@@ -227,11 +221,11 @@
+ * knows wiring of these extra pins, we use the map_irq function
+ * to get interrupts activated
+ */
-+static int ioc3_map_irq(struct pci_dev *pdev, int pin)
++static int ioc3_map_irq(struct pci_dev *pdev, int slot, int pin)
+{
+ struct pci_host_bridge *hbrg = pci_find_host_bridge(pdev->bus);
+
-+ return hbrg->map_irq(pdev, pin, 0);
++ return hbrg->map_irq(pdev, slot, pin);
+}
+
+static int ioc3_irq_domain_setup(struct ioc3_priv_data *ipd, int irq)
@@ -372,9 +366,8 @@
+ }
+};
+
-+static int ioc3_eth_setup(struct ioc3_priv_data *ipd, bool use_domain)
-+{
-+ int irq = ipd->pdev->irq;
++static int ioc3_eth_setup(struct ioc3_priv_data *ipd)
++{
+ int ret;
+
+ /* Enable One-Wire bus */
@@ -385,12 +378,9 @@
+ sizeof(ioc3_w1_platform_data.dev_id), "ioc3-%012llx",
+ ipd->pdev->resource->start);
+
-+ if (use_domain)
-+ irq = irq_create_mapping(ipd->domain, IOC3_IRQ_ETH_DOMAIN);
-+
+ ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO,
+ ioc3_eth_cells, ARRAY_SIZE(ioc3_eth_cells),
-+ &ipd->pdev->resource[0], irq, NULL);
++ &ipd->pdev->resource[0], ipd->pdev->irq, NULL);
+ if (ret) {
+ dev_err(&ipd->pdev->dev, "Failed to add ETH/W1 subdev\n");
+ return ret;
@@ -424,16 +414,86 @@
+ return ret;
+}
+
++static struct ds1685_rtc_platform_data ip30_rtc_platform_data = {
++ .bcd_mode = false,
++ .no_irq = false,
++ .uie_unsupported = true,
++ .access_type = ds1685_reg_indirect,
++};
++
++static struct resource ioc3_rtc_ds1685_resources[] = {
++ DEFINE_RES_MEM(IOC3_BYTEBUS_DEV1, 1),
++ DEFINE_RES_MEM(IOC3_BYTEBUS_DEV2, 1),
++ DEFINE_RES_IRQ(0)
++};
++
++static struct mfd_cell ioc3_ds1685_cells[] = {
++ {
++ .name = "rtc-ds1685",
++ .resources = ioc3_rtc_ds1685_resources,
++ .num_resources = ARRAY_SIZE(ioc3_rtc_ds1685_resources),
++ .platform_data = &ip30_rtc_platform_data,
++ .pdata_size = sizeof(ip30_rtc_platform_data),
++ .id = PLATFORM_DEVID_NONE,
++ }
++};
++
++static int ioc3_ds1685_setup(struct ioc3_priv_data *ipd)
++{
++ int ret, irq;
++
++ irq = ioc3_map_irq(ipd->pdev, 6, 0);
++
++ ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_ds1685_cells,
++ ARRAY_SIZE(ioc3_ds1685_cells),
++ &ipd->pdev->resource[0], irq, NULL);
++ if (ret)
++ dev_err(&ipd->pdev->dev, "Failed to add DS1685 subdev\n");
++
++ return ret;
++};
++
++
++static struct resource ioc3_leds_resources[] = {
++ DEFINE_RES_MEM(offsetof(struct ioc3, gppr[0]),
++ sizeof_field(struct ioc3, gppr[0])),
++ DEFINE_RES_MEM(offsetof(struct ioc3, gppr[1]),
++ sizeof_field(struct ioc3, gppr[1])),
++};
++
++static struct mfd_cell ioc3_led_cells[] = {
++ {
++ .name = "ip30-leds",
++ .resources = ioc3_leds_resources,
++ .num_resources = ARRAY_SIZE(ioc3_leds_resources),
++ .id = PLATFORM_DEVID_NONE,
++ }
++};
++
++static int ioc3_led_setup(struct ioc3_priv_data *ipd)
++{
++ int ret;
++
++ ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_led_cells,
++ ARRAY_SIZE(ioc3_led_cells),
++ &ipd->pdev->resource[0], 0, ipd->domain);
++ if (ret)
++ dev_err(&ipd->pdev->dev, "Failed to add LED subdev\n");
++
++ return ret;
++}
++
+static int ip27_baseio_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
-+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
++ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
++ PCI_INTERRUPT_INTB);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+
-+ ret = ioc3_eth_setup(ipd, false);
++ ret = ioc3_eth_setup(ipd);
+ if (ret)
+ return ret;
+
@@ -448,12 +508,13 @@
+{
+ int ret, io_irq;
+
-+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 2);
++ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
++ PCI_INTERRUPT_INTB);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+
-+ ret = ioc3_eth_setup(ipd, false);
++ ret = ioc3_eth_setup(ipd);
+ if (ret)
+ return ret;
+
@@ -483,16 +544,17 @@
+ return ioc3_kbd_setup(ipd);
+}
+
-+static int ip29_sysboard_setup(struct ioc3_priv_data *ipd)
++static int ip30_sysboard_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
-+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 1);
++ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
++ PCI_INTERRUPT_INTB);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+
-+ ret = ioc3_eth_setup(ipd, false);
++ ret = ioc3_eth_setup(ipd);
+ if (ret)
+ return ret;
+
@@ -500,23 +562,28 @@
+ if (ret)
+ return ret;
+
-+ ret = ioc3_m48t35_setup(ipd);
-+ if (ret)
-+ return ret;
-+
-+ return ioc3_kbd_setup(ipd);
++ ret = ioc3_kbd_setup(ipd);
++ if (ret)
++ return ret;
++
++ ret = ioc3_ds1685_setup(ipd);
++ if (ret)
++ return ret;
++
++ return ioc3_led_setup(ipd);
+}
+
+static int ioc3_menet_setup(struct ioc3_priv_data *ipd)
+{
+ int ret, io_irq;
+
-+ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn) + 4);
++ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
++ PCI_INTERRUPT_INTB);
+ ret = ioc3_irq_domain_setup(ipd, io_irq);
+ if (ret)
+ return ret;
+
-+ ret = ioc3_eth_setup(ipd, false);
++ ret = ioc3_eth_setup(ipd);
+ if (ret)
+ return ret;
+
@@ -525,18 +592,20 @@
+
+static int ioc3_menet4_setup(struct ioc3_priv_data *ipd)
+{
-+ return ioc3_eth_setup(ipd, false);
++ return ioc3_eth_setup(ipd);
+}
+
+static int ioc3_cad_duo_setup(struct ioc3_priv_data *ipd)
+{
-+ int ret;
-+
-+ ret = ioc3_irq_domain_setup(ipd, ipd->pdev->irq);
-+ if (ret)
-+ return ret;
-+
-+ ret = ioc3_eth_setup(ipd, true);
++ int ret, io_irq;
++
++ io_irq = ioc3_map_irq(ipd->pdev, PCI_SLOT(ipd->pdev->devfn),
++ PCI_INTERRUPT_INTB);
++ ret = ioc3_irq_domain_setup(ipd, io_irq);
++ if (ret)
++ return ret;
++
++ ret = ioc3_eth_setup(ipd);
+ if (ret)
+ return ret;
+
@@ -547,7 +616,7 @@
+#define IOC3_SID(_name, _sid, _setup) \
+ { \
+ .name = _name, \
-+ .sid = (PCI_VENDOR_ID_SGI << 16) | IOC3_SUBSYS_ ## _sid, \
++ .sid = PCI_VENDOR_ID_SGI | (IOC3_SUBSYS_ ## _sid << 16), \
+ .setup = _setup, \
+ }
+
@@ -559,7 +628,8 @@
+ IOC3_SID("IP27 BaseIO6G", IP27_BASEIO6G, &ip27_baseio6g_setup),
+ IOC3_SID("IP27 MIO", IP27_MIO, &ip27_mio_setup),
+ IOC3_SID("IP27 BaseIO", IP27_BASEIO, &ip27_baseio_setup),
-+ IOC3_SID("IP29 System Board", IP29_SYSBOARD, &ip29_sysboard_setup),
++ IOC3_SID("IP29 System Board", IP29_SYSBOARD, &ip27_baseio6g_setup),
++ IOC3_SID("IP30 System Board", IP30_SYSBOARD, &ip30_sysboard_setup),
+ IOC3_SID("MENET", MENET, &ioc3_menet_setup),
+ IOC3_SID("MENET4", MENET4, &ioc3_menet4_setup)
+};
@@ -606,13 +676,9 @@
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret) {
-+ dev_warn(&pdev->dev,
-+ "Failed to set 64-bit DMA mask, trying 32-bit\n");
-+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-+ if (ret) {
-+ dev_err(&pdev->dev, "Can't set DMA mask, aborting\n");
-+ goto out_disable_device;
-+ }
++ pr_err("%s: No usable DMA configuration, aborting.\n",
++ pci_name(pdev));
++ goto out_disable_device;
+ }
+
+ /* Set up per-IOC3 data */
@@ -721,7 +787,7 @@
select MII
---help---
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
-index deb636d653f3..9a86156acbdf 100644
+index 4ebb58b8572e..fa1c16f96065 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -14,7 +14,6 @@
@@ -757,7 +823,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
- #include <linux/dma-direct.h>
+ #include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/nvmem-consumer.h>
@@ -784,7 +850,7 @@
struct device *dma_dev;
u32 *ssram;
unsigned long *rxr; /* pointer to receiver ring */
-@@ -103,9 +96,6 @@ struct ioc3_private {
+@@ -104,9 +97,6 @@ struct ioc3_private {
spinlock_t ioc3_lock;
struct mii_if_info mii;
@@ -794,7 +860,7 @@
/* Members used by autonegotiation */
struct timer_list ioc3_timer;
};
-@@ -122,10 +112,8 @@ static int ioc3_alloc_rx_bufs(struct net_device *dev);
+@@ -123,10 +113,8 @@ static int ioc3_alloc_rx_bufs(struct net_device *dev);
static void ioc3_free_rx_bufs(struct ioc3_private *ip);
static inline void ioc3_clean_tx_ring(struct ioc3_private *ip);
@@ -805,7 +871,7 @@
static inline unsigned long aligned_rx_skb_addr(unsigned long addr)
{
return (~addr + 1) & (IOC3_DMA_XFER_LEN - 1UL);
-@@ -178,225 +166,61 @@ static inline unsigned long ioc3_map(dma_addr_t addr, unsigned long attr)
+@@ -179,225 +167,61 @@ static inline unsigned long ioc3_map(dma_addr_t addr, unsigned long attr)
#define ERBAR_VAL 0
#endif
@@ -1070,7 +1136,7 @@
}
static void __ioc3_set_mac_address(struct net_device *dev)
-@@ -769,7 +593,7 @@ static int ioc3_mii_init(struct ioc3_private *ip)
+@@ -770,7 +594,7 @@ static int ioc3_mii_init(struct ioc3_private *ip)
u16 word;
for (i = 0; i < 32; i++) {
@@ -1079,7 +1145,7 @@
if (word != 0xffff && word != 0x0000) {
found = 1;
-@@ -974,12 +798,6 @@ static int ioc3_open(struct net_device *dev)
+@@ -975,12 +799,6 @@ static int ioc3_open(struct net_device *dev)
{
struct ioc3_private *ip = netdev_priv(dev);
@@ -1092,7 +1158,7 @@
ip->ehar_h = 0;
ip->ehar_l = 0;
-@@ -1012,147 +830,6 @@ static int ioc3_close(struct net_device *dev)
+@@ -1013,159 +831,6 @@ static int ioc3_close(struct net_device *dev)
return 0;
}
@@ -1162,6 +1228,16 @@
- * Can't use UPF_IOREMAP as the whole of IOC3 resources have already been
- * registered.
- */
+-static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
+-{
+- return readb(p->membase + (offset ^ 3));
+-}
+-
+-static void ioc3_serial_out(struct uart_port *p, int offset, int value)
+-{
+- writeb(value, p->membase + (offset ^ 3));
+-}
+-
-static void ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
-{
-#define COSMISC_CONSTANT 6
@@ -1176,6 +1252,8 @@
-
- .membase = (unsigned char __iomem *)uart,
- .mapbase = (unsigned long)uart,
+- .serial_in = ioc3_serial_in,
+- .serial_out = ioc3_serial_out,
- }
- };
- unsigned char lcr;
@@ -1240,7 +1318,7 @@
static const struct net_device_ops ioc3_netdev_ops = {
.ndo_open = ioc3_open,
.ndo_stop = ioc3_close,
-@@ -1165,76 +842,52 @@ static const struct net_device_ops ioc3_netdev_ops = {
+@@ -1178,61 +843,52 @@ static const struct net_device_ops ioc3_netdev_ops = {
.ndo_set_mac_address = ioc3_set_mac_address,
};
@@ -1254,32 +1332,19 @@
- struct ioc3 *ioc3;
- unsigned long ioc3_base, ioc3_size;
- u32 vendor, model, rev;
-- int err, pci_using_dac;
--
-- /* Configure DMA attributes. */
-- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-- if (!err) {
-- pci_using_dac = 1;
-- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-- if (err < 0) {
-- pr_err("%s: Unable to obtain 64 bit DMA for consistent allocations\n",
-- pci_name(pdev));
-- goto out;
-- }
-- } else {
-- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-- if (err) {
-- pr_err("%s: No usable DMA configuration, aborting.\n",
-- pci_name(pdev));
-- goto out;
-- }
-- pci_using_dac = 0;
-- }
+ struct net_device *dev;
+ struct resource *regs;
+ u8 mac_addr[6];
-+ int err;
-
+ int err;
+
+- /* Configure DMA attributes. */
+- err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+- if (err) {
+- pr_err("%s: No usable DMA configuration, aborting.\n",
+- pci_name(pdev));
+- goto out;
+- }
+-
- if (pci_enable_device(pdev))
- return -ENODEV;
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1292,9 +1357,6 @@
- err = -ENOMEM;
- goto out_disable;
- }
--
-- if (pci_using_dac)
-- dev->features |= NETIF_F_HIGHDMA;
-
- err = pci_request_regions(pdev, "ioc3");
- if (err)
@@ -1350,7 +1412,7 @@
spin_lock_init(&ip->ioc3_lock);
timer_setup(&ip->ioc3_timer, ioc3_timer, 0);
-@@ -1262,8 +915,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -1262,8 +918,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ioc3_init(dev);
@@ -1359,7 +1421,7 @@
ip->mii.phy_id_mask = 0x1f;
ip->mii.reg_num_mask = 0x1f;
ip->mii.dev = dev;
-@@ -1273,15 +924,14 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+@@ -1273,15 +927,14 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ioc3_mii_init(ip);
if (ip->mii.phy_id == -1) {
@@ -1377,10 +1439,10 @@
/* The IOC3-specific entries in the device structure. */
dev->watchdog_timeo = 5 * HZ;
-@@ -1318,21 +968,14 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
- if (ip->txr)
- dma_direct_free_pages(ip->dma_dev, TX_RING_SIZE, ip->txr,
- ip->txr_dma, 0);
+@@ -1318,21 +971,14 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+ if (ip->tx_ring)
+ dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->tx_ring,
+ ip->txr_dma);
-out_res:
- pci_release_regions(pdev);
out_free:
@@ -1400,8 +1462,8 @@
+ struct net_device *dev = platform_get_drvdata(pdev);
struct ioc3_private *ip = netdev_priv(dev);
- dma_direct_free_pages(ip->dma_dev, RX_RING_SIZE, ip->rxr,
-@@ -1342,27 +985,11 @@ static void ioc3_remove_one(struct pci_dev *pdev)
+ dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr, ip->rxr_dma);
+@@ -1340,27 +986,11 @@ static void ioc3_remove_one(struct pci_dev *pdev)
unregister_netdev(dev);
del_timer_sync(&ip->ioc3_timer);
@@ -1431,7 +1493,7 @@
static netdev_tx_t ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
-@@ -1544,11 +1171,10 @@ static inline unsigned int ioc3_hash(const unsigned char *addr)
+@@ -1542,11 +1172,10 @@ static inline unsigned int ioc3_hash(const unsigned char *addr)
static void ioc3_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
@@ -1445,7 +1507,7 @@
}
static int ioc3_get_link_ksettings(struct net_device *dev,
-@@ -1660,7 +1286,16 @@ static void ioc3_set_multicast_list(struct net_device *dev)
+@@ -1658,7 +1287,16 @@ static void ioc3_set_multicast_list(struct net_device *dev)
spin_unlock_irq(&ip->ioc3_lock);
}
@@ -1465,7 +1527,7 @@
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
new file mode 100644
-index 000000000000..2be6ed2967e0
+index 000000000000..4c405f1b9c67
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -0,0 +1,98 @@
@@ -1494,12 +1556,12 @@
+
+static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
+{
-+ return readb(p->membase + offset);
++ return readb(p->membase + (offset ^ 3));
+}
+
+static void ioc3_serial_out(struct uart_port *p, int offset, int value)
+{
-+ writeb(value, p->membase + offset);
++ writeb(value, p->membase + (offset ^ 3));
+}
+
+static int serial8250_ioc3_probe(struct platform_device *pdev)
@@ -1568,10 +1630,10 @@
+MODULE_DESCRIPTION("SGI IOC3 8250 UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
-index 7ef60f8b6e2c..536808506545 100644
+index fab3d4f20667..af69a5d4ba48 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
-@@ -370,6 +370,17 @@ config SERIAL_8250_EM
+@@ -371,6 +371,17 @@ config SERIAL_8250_EM
port hardware found on the Emma Mobile line of processors.
If unsure, say N.
@@ -1602,5 +1664,5 @@
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
--
-2.16.4
+2.24.1