aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-16 15:32:01 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-16 15:32:01 -0700
commit76f0f227cffb570bc5ce343b1750f14907371d80 (patch)
tree7bbbf7174a7c7cc834936a18a73fc95161b4228e /drivers
parentMerge tag 'riscv/for-v5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux (diff)
parentgenirq: remove the is_affinity_mask_valid hook (diff)
downloadlinux-dev-76f0f227cffb570bc5ce343b1750f14907371d80.tar.xz
linux-dev-76f0f227cffb570bc5ce343b1750f14907371d80.zip
Merge tag 'please-pull-ia64_for_5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
Pull ia64 updates from Tony Luck: "The big change here is removal of support for SGI Altix" * tag 'please-pull-ia64_for_5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux: (33 commits) genirq: remove the is_affinity_mask_valid hook ia64: remove CONFIG_SWIOTLB ifdefs ia64: remove support for machvecs ia64: move the screen_info setup to common code ia64: move the ROOT_DEV setup to common code ia64: rework iommu probing ia64: remove the unused sn_coherency_id symbol ia64: remove the SGI UV simulator support ia64: remove the zx1 swiotlb machvec ia64: remove CONFIG_ACPI ifdefs ia64: remove CONFIG_PCI ifdefs ia64: remove the hpsim platform ia64: remove now unused machvec indirections ia64: remove support for the SGI SN2 platform drivers: remove the SGI SN2 IOC4 base support drivers: remove the SGI SN2 IOC3 base support qla2xxx: remove SGI SN2 support qla1280: remove SGI SN2 support misc/sgi-xp: remove SGI SN2 support char/mspec: remove SGI SN2 support ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/char/Kconfig22
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/agp/Kconfig11
-rw-r--r--drivers/char/agp/Makefile1
-rw-r--r--drivers/char/agp/sgi-agp.c338
-rw-r--r--drivers/char/mbcs.c831
-rw-r--r--drivers/char/mbcs.h553
-rw-r--r--drivers/char/mspec.c155
-rw-r--r--drivers/char/snsc.c469
-rw-r--r--drivers/char/snsc.h92
-rw-r--r--drivers/char/snsc_event.c303
-rw-r--r--drivers/ide/Kconfig9
-rw-r--r--drivers/ide/Makefile1
-rw-r--r--drivers/ide/sgiioc4.c630
-rw-r--r--drivers/iommu/Kconfig2
-rw-r--r--drivers/misc/Kconfig17
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/ioc4.c498
-rw-r--r--drivers/misc/sgi-xp/Makefile13
-rw-r--r--drivers/misc/sgi-xp/xp.h19
-rw-r--r--drivers/misc/sgi-xp/xp_main.c8
-rw-r--r--drivers/misc/sgi-xp/xp_nofault.S35
-rw-r--r--drivers/misc/sgi-xp/xp_sn2.c190
-rw-r--r--drivers/misc/sgi-xp/xp_uv.c9
-rw-r--r--drivers/misc/sgi-xp/xpc.h273
-rw-r--r--drivers/misc/sgi-xp/xpc_main.c31
-rw-r--r--drivers/misc/sgi-xp/xpc_partition.c5
-rw-r--r--drivers/misc/sgi-xp/xpc_sn2.c2459
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c16
-rw-r--r--drivers/misc/sgi-xp/xpnet.c2
-rw-r--r--drivers/pci/hotplug/Kconfig9
-rw-r--r--drivers/pci/hotplug/Makefile1
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c700
-rw-r--r--drivers/scsi/qla1280.c37
-rw-r--r--drivers/scsi/qla1280.h3
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c14
-rw-r--r--drivers/sn/Kconfig22
-rw-r--r--drivers/sn/Makefile7
-rw-r--r--drivers/sn/ioc3.c844
-rw-r--r--drivers/tty/serial/Kconfig27
-rw-r--r--drivers/tty/serial/Makefile3
-rw-r--r--drivers/tty/serial/ioc3_serial.c2195
-rw-r--r--drivers/tty/serial/ioc4_serial.c2955
-rw-r--r--drivers/tty/serial/sn_console.c1036
47 files changed, 40 insertions, 14813 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 61cf4ea2c229..477d63d0364d 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -30,8 +30,6 @@ source "drivers/block/Kconfig"
source "drivers/nvme/Kconfig"
-# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4
-
source "drivers/misc/Kconfig"
source "drivers/ide/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 6d37564e783c..05be8c798c51 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -132,7 +132,6 @@ obj-y += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-$(CONFIG_NEW_LEDS) += leds/
obj-$(CONFIG_INFINIBAND) += infiniband/
-obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 5f6158973289..ebe1e9e5fd81 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -323,7 +323,7 @@ config ACPI_NUMA
bool "NUMA support"
depends on NUMA
depends on (X86 || IA64 || ARM64)
- default y if IA64_GENERIC || IA64_SGI_SN2 || ARM64
+ default y if IA64 || ARM64
config ACPI_CUSTOM_DSDT_FILE
string "Custom DSDT Table file to include"
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 2794f4b3f62d..df0fc997dc3e 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -26,28 +26,6 @@ config DEVKMEM
kind of kernel debugging operations.
When in doubt, say "N".
-config SGI_SNSC
- bool "SGI Altix system controller communication support"
- depends on (IA64_SGI_SN2 || IA64_GENERIC)
- help
- If you have an SGI Altix and you want to enable system
- controller communication from user space (you want this!),
- say Y. Otherwise, say N.
-
-config SGI_TIOCX
- bool "SGI TIO CX driver support"
- depends on (IA64_SGI_SN2 || IA64_GENERIC)
- help
- If you have an SGI Altix and you have fpga devices attached
- to your TIO, say Y here, otherwise say N.
-
-config SGI_MBCS
- tristate "SGI FPGA Core Services driver support"
- depends on SGI_TIOCX
- help
- If you have an SGI Altix with an attached SABrick
- say Y or M here, otherwise say N.
-
source "drivers/tty/serial/Kconfig"
source "drivers/tty/serdev/Kconfig"
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index fbea7dd12932..7c5ea6f9df14 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -9,11 +9,9 @@ obj-y += misc.o
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
-obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
obj-$(CONFIG_IBM_BSR) += bsr.o
-obj-$(CONFIG_SGI_MBCS) += mbcs.o
obj-$(CONFIG_PRINTER) += lp.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 6231714ef3c8..812d6aa6e013 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -111,14 +111,14 @@ config AGP_VIA
config AGP_I460
tristate "Intel 460GX chipset support"
- depends on AGP && (IA64_DIG || IA64_GENERIC)
+ depends on AGP && IA64
help
This option gives you AGP GART support for the Intel 460GX chipset
for IA64 processors.
config AGP_HP_ZX1
tristate "HP ZX1 chipset AGP support"
- depends on AGP && (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC)
+ depends on AGP && IA64
help
This option gives you AGP GART support for the HP ZX1 chipset
for IA64 processors.
@@ -150,13 +150,6 @@ config AGP_EFFICEON
This option gives you AGP support for the Transmeta Efficeon
series processors with integrated northbridges.
-config AGP_SGI_TIOCA
- tristate "SGI TIO chipset AGP support"
- depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC)
- help
- This option gives you AGP GART support for the SGI TIO chipset
- for IA64 processors.
-
config INTEL_GTT
tristate
depends on X86 && PCI
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 4a786ffd9dee..cb2497d157f6 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_INTEL) += intel-agp.o
obj-$(CONFIG_INTEL_GTT) += intel-gtt.o
obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
-obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o
obj-$(CONFIG_AGP_SIS) += sis-agp.o
obj-$(CONFIG_AGP_SWORKS) += sworks-agp.o
obj-$(CONFIG_AGP_UNINORTH) += uninorth-agp.o
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
deleted file mode 100644
index e7d5bdc02d93..000000000000
--- a/drivers/char/agp/sgi-agp.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved.
- */
-
-/*
- * SGI TIOCA AGPGART routines.
- *
- */
-
-#include <linux/acpi.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/agp_backend.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/io.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/tioca_provider.h>
-#include "agp.h"
-
-extern int agp_memory_reserved;
-extern uint32_t tioca_gart_found;
-extern struct list_head tioca_list;
-static struct agp_bridge_data **sgi_tioca_agp_bridges;
-
-/*
- * The aperature size and related information is set up at TIOCA init time.
- * Values for this table will be extracted and filled in at
- * sgi_tioca_fetch_size() time.
- */
-
-static struct aper_size_info_fixed sgi_tioca_sizes[] = {
- {0, 0, 0},
-};
-
-static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
-{
- struct page *page;
- int nid;
- struct tioca_kernel *info =
- (struct tioca_kernel *)bridge->dev_private_data;
-
- nid = info->ca_closest_node;
- page = alloc_pages_node(nid, GFP_KERNEL, 0);
- if (!page)
- return NULL;
-
- get_page(page);
- atomic_inc(&agp_bridge->current_memory_agp);
- return page;
-}
-
-/*
- * Flush GART tlb's. Cannot selectively flush based on memory so the mem
- * arg is ignored.
- */
-
-static void sgi_tioca_tlbflush(struct agp_memory *mem)
-{
- tioca_tlbflush(mem->bridge->dev_private_data);
-}
-
-/*
- * Given an address of a host physical page, turn it into a valid gart
- * entry.
- */
-static unsigned long
-sgi_tioca_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
- int type)
-{
- return tioca_physpage_to_gart(addr);
-}
-
-static void sgi_tioca_agp_enable(struct agp_bridge_data *bridge, u32 mode)
-{
- tioca_fastwrite_enable(bridge->dev_private_data);
-}
-
-/*
- * sgi_tioca_configure() doesn't have anything to do since the base CA driver
- * has alreay set up the GART.
- */
-
-static int sgi_tioca_configure(void)
-{
- return 0;
-}
-
-/*
- * Determine gfx aperature size. This has already been determined by the
- * CA driver init, so just need to set agp_bridge values accordingly.
- */
-
-static int sgi_tioca_fetch_size(void)
-{
- struct tioca_kernel *info =
- (struct tioca_kernel *)agp_bridge->dev_private_data;
-
- sgi_tioca_sizes[0].size = info->ca_gfxap_size / MB(1);
- sgi_tioca_sizes[0].num_entries = info->ca_gfxgart_entries;
-
- return sgi_tioca_sizes[0].size;
-}
-
-static int sgi_tioca_create_gatt_table(struct agp_bridge_data *bridge)
-{
- struct tioca_kernel *info =
- (struct tioca_kernel *)bridge->dev_private_data;
-
- bridge->gatt_table_real = (u32 *) info->ca_gfxgart;
- bridge->gatt_table = bridge->gatt_table_real;
- bridge->gatt_bus_addr = info->ca_gfxgart_base;
-
- return 0;
-}
-
-static int sgi_tioca_free_gatt_table(struct agp_bridge_data *bridge)
-{
- return 0;
-}
-
-static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
- int type)
-{
- int num_entries;
- size_t i;
- off_t j;
- void *temp;
- struct agp_bridge_data *bridge;
- u64 *table;
-
- bridge = mem->bridge;
- if (!bridge)
- return -EINVAL;
-
- table = (u64 *)bridge->gatt_table;
-
- temp = bridge->current_size;
-
- switch (bridge->driver->size_type) {
- case U8_APER_SIZE:
- num_entries = A_SIZE_8(temp)->num_entries;
- break;
- case U16_APER_SIZE:
- num_entries = A_SIZE_16(temp)->num_entries;
- break;
- case U32_APER_SIZE:
- num_entries = A_SIZE_32(temp)->num_entries;
- break;
- case FIXED_APER_SIZE:
- num_entries = A_SIZE_FIX(temp)->num_entries;
- break;
- case LVL2_APER_SIZE:
- return -EINVAL;
- default:
- num_entries = 0;
- break;
- }
-
- num_entries -= agp_memory_reserved / PAGE_SIZE;
- if (num_entries < 0)
- num_entries = 0;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
-
- if ((pg_start + mem->page_count) > num_entries)
- return -EINVAL;
-
- j = pg_start;
-
- while (j < (pg_start + mem->page_count)) {
- if (table[j])
- return -EBUSY;
- j++;
- }
-
- if (!mem->is_flushed) {
- bridge->driver->cache_flush();
- mem->is_flushed = true;
- }
-
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- table[j] =
- bridge->driver->mask_memory(bridge,
- page_to_phys(mem->pages[i]),
- mem->type);
- }
-
- bridge->driver->tlb_flush(mem);
- return 0;
-}
-
-static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start,
- int type)
-{
- size_t i;
- struct agp_bridge_data *bridge;
- u64 *table;
-
- bridge = mem->bridge;
- if (!bridge)
- return -EINVAL;
-
- if (type != 0 || mem->type != 0) {
- return -EINVAL;
- }
-
- table = (u64 *)bridge->gatt_table;
-
- for (i = pg_start; i < (mem->page_count + pg_start); i++) {
- table[i] = 0;
- }
-
- bridge->driver->tlb_flush(mem);
- return 0;
-}
-
-static void sgi_tioca_cache_flush(void)
-{
-}
-
-/*
- * Cleanup. Nothing to do as the CA driver owns the GART.
- */
-
-static void sgi_tioca_cleanup(void)
-{
-}
-
-static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
-{
- struct agp_bridge_data *bridge;
-
- list_for_each_entry(bridge, &agp_bridges, list) {
- if (bridge->dev->bus == pdev->bus)
- break;
- }
- return bridge;
-}
-
-const struct agp_bridge_driver sgi_tioca_driver = {
- .owner = THIS_MODULE,
- .size_type = U16_APER_SIZE,
- .configure = sgi_tioca_configure,
- .fetch_size = sgi_tioca_fetch_size,
- .cleanup = sgi_tioca_cleanup,
- .tlb_flush = sgi_tioca_tlbflush,
- .mask_memory = sgi_tioca_mask_memory,
- .agp_enable = sgi_tioca_agp_enable,
- .cache_flush = sgi_tioca_cache_flush,
- .create_gatt_table = sgi_tioca_create_gatt_table,
- .free_gatt_table = sgi_tioca_free_gatt_table,
- .insert_memory = sgi_tioca_insert_memory,
- .remove_memory = sgi_tioca_remove_memory,
- .alloc_by_type = agp_generic_alloc_by_type,
- .free_by_type = agp_generic_free_by_type,
- .agp_alloc_page = sgi_tioca_alloc_page,
- .agp_destroy_page = agp_generic_destroy_page,
- .agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .cant_use_aperture = true,
- .needs_scratch_page = false,
- .num_aperture_sizes = 1,
-};
-
-static int agp_sgi_init(void)
-{
- unsigned int j;
- struct tioca_kernel *info;
- struct pci_dev *pdev = NULL;
-
- if (tioca_gart_found)
- printk(KERN_INFO PFX "SGI TIO CA GART driver initialized.\n");
- else
- return 0;
-
- sgi_tioca_agp_bridges = kmalloc_array(tioca_gart_found,
- sizeof(struct agp_bridge_data *),
- GFP_KERNEL);
- if (!sgi_tioca_agp_bridges)
- return -ENOMEM;
-
- j = 0;
- list_for_each_entry(info, &tioca_list, ca_list) {
- if (list_empty(info->ca_devices))
- continue;
- list_for_each_entry(pdev, info->ca_devices, bus_list) {
- u8 cap_ptr;
-
- if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
- continue;
- cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
- if (!cap_ptr)
- continue;
- }
- sgi_tioca_agp_bridges[j] = agp_alloc_bridge();
- printk(KERN_INFO PFX "bridge %d = 0x%p\n", j,
- sgi_tioca_agp_bridges[j]);
- if (sgi_tioca_agp_bridges[j]) {
- sgi_tioca_agp_bridges[j]->dev = pdev;
- sgi_tioca_agp_bridges[j]->dev_private_data = info;
- sgi_tioca_agp_bridges[j]->driver = &sgi_tioca_driver;
- sgi_tioca_agp_bridges[j]->gart_bus_addr =
- info->ca_gfxap_base;
- sgi_tioca_agp_bridges[j]->mode = (0x7D << 24) | /* 126 requests */
- (0x1 << 9) | /* SBA supported */
- (0x1 << 5) | /* 64-bit addresses supported */
- (0x1 << 4) | /* FW supported */
- (0x1 << 3) | /* AGP 3.0 mode */
- 0x2; /* 8x transfer only */
- sgi_tioca_agp_bridges[j]->current_size =
- sgi_tioca_agp_bridges[j]->previous_size =
- (void *)&sgi_tioca_sizes[0];
- agp_add_bridge(sgi_tioca_agp_bridges[j]);
- }
- j++;
- }
-
- agp_find_bridge = &sgi_tioca_find_bridge;
- return 0;
-}
-
-static void agp_sgi_cleanup(void)
-{
- kfree(sgi_tioca_agp_bridges);
- sgi_tioca_agp_bridges = NULL;
-}
-
-module_init(agp_sgi_init);
-module_exit(agp_sgi_cleanup);
-
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
deleted file mode 100644
index 0a31b60bee7b..000000000000
--- a/drivers/char/mbcs.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * MOATB Core Services driver.
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/uio.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <asm/io.h>
-#include <linux/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/tiocx.h>
-#include "mbcs.h"
-
-#define MBCS_DEBUG 0
-#if MBCS_DEBUG
-#define DBG(fmt...) printk(KERN_ALERT fmt)
-#else
-#define DBG(fmt...)
-#endif
-static DEFINE_MUTEX(mbcs_mutex);
-static int mbcs_major;
-
-static LIST_HEAD(soft_list);
-
-/*
- * file operations
- */
-static const struct file_operations mbcs_ops = {
- .owner = THIS_MODULE,
- .open = mbcs_open,
- .llseek = mbcs_sram_llseek,
- .read = mbcs_sram_read,
- .write = mbcs_sram_write,
- .mmap = mbcs_gscr_mmap,
-};
-
-struct mbcs_callback_arg {
- int minor;
- struct cx_dev *cx_dev;
-};
-
-static inline void mbcs_getdma_init(struct getdma *gdma)
-{
- memset(gdma, 0, sizeof(struct getdma));
- gdma->DoneIntEnable = 1;
-}
-
-static inline void mbcs_putdma_init(struct putdma *pdma)
-{
- memset(pdma, 0, sizeof(struct putdma));
- pdma->DoneIntEnable = 1;
-}
-
-static inline void mbcs_algo_init(struct algoblock *algo_soft)
-{
- memset(algo_soft, 0, sizeof(struct algoblock));
-}
-
-static inline void mbcs_getdma_set(void *mmr,
- uint64_t hostAddr,
- uint64_t localAddr,
- uint64_t localRamSel,
- uint64_t numPkts,
- uint64_t amoEnable,
- uint64_t intrEnable,
- uint64_t peerIO,
- uint64_t amoHostDest,
- uint64_t amoModType, uint64_t intrHostDest,
- uint64_t intrVector)
-{
- union dma_control rdma_control;
- union dma_amo_dest amo_dest;
- union intr_dest intr_dest;
- union dma_localaddr local_addr;
- union dma_hostaddr host_addr;
-
- rdma_control.dma_control_reg = 0;
- amo_dest.dma_amo_dest_reg = 0;
- intr_dest.intr_dest_reg = 0;
- local_addr.dma_localaddr_reg = 0;
- host_addr.dma_hostaddr_reg = 0;
-
- host_addr.dma_sys_addr = hostAddr;
- MBCS_MMR_SET(mmr, MBCS_RD_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
-
- local_addr.dma_ram_addr = localAddr;
- local_addr.dma_ram_sel = localRamSel;
- MBCS_MMR_SET(mmr, MBCS_RD_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
-
- rdma_control.dma_op_length = numPkts;
- rdma_control.done_amo_en = amoEnable;
- rdma_control.done_int_en = intrEnable;
- rdma_control.pio_mem_n = peerIO;
- MBCS_MMR_SET(mmr, MBCS_RD_DMA_CTRL, rdma_control.dma_control_reg);
-
- amo_dest.dma_amo_sys_addr = amoHostDest;
- amo_dest.dma_amo_mod_type = amoModType;
- MBCS_MMR_SET(mmr, MBCS_RD_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
-
- intr_dest.address = intrHostDest;
- intr_dest.int_vector = intrVector;
- MBCS_MMR_SET(mmr, MBCS_RD_DMA_INT_DEST, intr_dest.intr_dest_reg);
-
-}
-
-static inline void mbcs_putdma_set(void *mmr,
- uint64_t hostAddr,
- uint64_t localAddr,
- uint64_t localRamSel,
- uint64_t numPkts,
- uint64_t amoEnable,
- uint64_t intrEnable,
- uint64_t peerIO,
- uint64_t amoHostDest,
- uint64_t amoModType,
- uint64_t intrHostDest, uint64_t intrVector)
-{
- union dma_control wdma_control;
- union dma_amo_dest amo_dest;
- union intr_dest intr_dest;
- union dma_localaddr local_addr;
- union dma_hostaddr host_addr;
-
- wdma_control.dma_control_reg = 0;
- amo_dest.dma_amo_dest_reg = 0;
- intr_dest.intr_dest_reg = 0;
- local_addr.dma_localaddr_reg = 0;
- host_addr.dma_hostaddr_reg = 0;
-
- host_addr.dma_sys_addr = hostAddr;
- MBCS_MMR_SET(mmr, MBCS_WR_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
-
- local_addr.dma_ram_addr = localAddr;
- local_addr.dma_ram_sel = localRamSel;
- MBCS_MMR_SET(mmr, MBCS_WR_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
-
- wdma_control.dma_op_length = numPkts;
- wdma_control.done_amo_en = amoEnable;
- wdma_control.done_int_en = intrEnable;
- wdma_control.pio_mem_n = peerIO;
- MBCS_MMR_SET(mmr, MBCS_WR_DMA_CTRL, wdma_control.dma_control_reg);
-
- amo_dest.dma_amo_sys_addr = amoHostDest;
- amo_dest.dma_amo_mod_type = amoModType;
- MBCS_MMR_SET(mmr, MBCS_WR_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
-
- intr_dest.address = intrHostDest;
- intr_dest.int_vector = intrVector;
- MBCS_MMR_SET(mmr, MBCS_WR_DMA_INT_DEST, intr_dest.intr_dest_reg);
-
-}
-
-static inline void mbcs_algo_set(void *mmr,
- uint64_t amoHostDest,
- uint64_t amoModType,
- uint64_t intrHostDest,
- uint64_t intrVector, uint64_t algoStepCount)
-{
- union dma_amo_dest amo_dest;
- union intr_dest intr_dest;
- union algo_step step;
-
- step.algo_step_reg = 0;
- intr_dest.intr_dest_reg = 0;
- amo_dest.dma_amo_dest_reg = 0;
-
- amo_dest.dma_amo_sys_addr = amoHostDest;
- amo_dest.dma_amo_mod_type = amoModType;
- MBCS_MMR_SET(mmr, MBCS_ALG_AMO_DEST, amo_dest.dma_amo_dest_reg);
-
- intr_dest.address = intrHostDest;
- intr_dest.int_vector = intrVector;
- MBCS_MMR_SET(mmr, MBCS_ALG_INT_DEST, intr_dest.intr_dest_reg);
-
- step.alg_step_cnt = algoStepCount;
- MBCS_MMR_SET(mmr, MBCS_ALG_STEP, step.algo_step_reg);
-}
-
-static inline int mbcs_getdma_start(struct mbcs_soft *soft)
-{
- void *mmr_base;
- struct getdma *gdma;
- uint64_t numPkts;
- union cm_control cm_control;
-
- mmr_base = soft->mmr_base;
- gdma = &soft->getdma;
-
- /* check that host address got setup */
- if (!gdma->hostAddr)
- return -1;
-
- numPkts =
- (gdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
-
- /* program engine */
- mbcs_getdma_set(mmr_base, tiocx_dma_addr(gdma->hostAddr),
- gdma->localAddr,
- (gdma->localAddr < MB2) ? 0 :
- (gdma->localAddr < MB4) ? 1 :
- (gdma->localAddr < MB6) ? 2 : 3,
- numPkts,
- gdma->DoneAmoEnable,
- gdma->DoneIntEnable,
- gdma->peerIO,
- gdma->amoHostDest,
- gdma->amoModType,
- gdma->intrHostDest, gdma->intrVector);
-
- /* start engine */
- cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
- cm_control.rd_dma_go = 1;
- MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
- return 0;
-
-}
-
-static inline int mbcs_putdma_start(struct mbcs_soft *soft)
-{
- void *mmr_base;
- struct putdma *pdma;
- uint64_t numPkts;
- union cm_control cm_control;
-
- mmr_base = soft->mmr_base;
- pdma = &soft->putdma;
-
- /* check that host address got setup */
- if (!pdma->hostAddr)
- return -1;
-
- numPkts =
- (pdma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
-
- /* program engine */
- mbcs_putdma_set(mmr_base, tiocx_dma_addr(pdma->hostAddr),
- pdma->localAddr,
- (pdma->localAddr < MB2) ? 0 :
- (pdma->localAddr < MB4) ? 1 :
- (pdma->localAddr < MB6) ? 2 : 3,
- numPkts,
- pdma->DoneAmoEnable,
- pdma->DoneIntEnable,
- pdma->peerIO,
- pdma->amoHostDest,
- pdma->amoModType,
- pdma->intrHostDest, pdma->intrVector);
-
- /* start engine */
- cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
- cm_control.wr_dma_go = 1;
- MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
- return 0;
-
-}
-
-static inline int mbcs_algo_start(struct mbcs_soft *soft)
-{
- struct algoblock *algo_soft = &soft->algo;
- void *mmr_base = soft->mmr_base;
- union cm_control cm_control;
-
- if (mutex_lock_interruptible(&soft->algolock))
- return -ERESTARTSYS;
-
- atomic_set(&soft->algo_done, 0);
-
- mbcs_algo_set(mmr_base,
- algo_soft->amoHostDest,
- algo_soft->amoModType,
- algo_soft->intrHostDest,
- algo_soft->intrVector, algo_soft->algoStepCount);
-
- /* start algorithm */
- cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
- cm_control.alg_done_int_en = 1;
- cm_control.alg_go = 1;
- MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
- mutex_unlock(&soft->algolock);
-
- return 0;
-}
-
-static inline ssize_t
-do_mbcs_sram_dmawrite(struct mbcs_soft *soft, uint64_t hostAddr,
- size_t len, loff_t * off)
-{
- int rv = 0;
-
- if (mutex_lock_interruptible(&soft->dmawritelock))
- return -ERESTARTSYS;
-
- atomic_set(&soft->dmawrite_done, 0);
-
- soft->putdma.hostAddr = hostAddr;
- soft->putdma.localAddr = *off;
- soft->putdma.bytes = len;
-
- if (mbcs_putdma_start(soft) < 0) {
- DBG(KERN_ALERT "do_mbcs_sram_dmawrite: "
- "mbcs_putdma_start failed\n");
- rv = -EAGAIN;
- goto dmawrite_exit;
- }
-
- if (wait_event_interruptible(soft->dmawrite_queue,
- atomic_read(&soft->dmawrite_done))) {
- rv = -ERESTARTSYS;
- goto dmawrite_exit;
- }
-
- rv = len;
- *off += len;
-
-dmawrite_exit:
- mutex_unlock(&soft->dmawritelock);
-
- return rv;
-}
-
-static inline ssize_t
-do_mbcs_sram_dmaread(struct mbcs_soft *soft, uint64_t hostAddr,
- size_t len, loff_t * off)
-{
- int rv = 0;
-
- if (mutex_lock_interruptible(&soft->dmareadlock))
- return -ERESTARTSYS;
-
- atomic_set(&soft->dmawrite_done, 0);
-
- soft->getdma.hostAddr = hostAddr;
- soft->getdma.localAddr = *off;
- soft->getdma.bytes = len;
-
- if (mbcs_getdma_start(soft) < 0) {
- DBG(KERN_ALERT "mbcs_strategy: mbcs_getdma_start failed\n");
- rv = -EAGAIN;
- goto dmaread_exit;
- }
-
- if (wait_event_interruptible(soft->dmaread_queue,
- atomic_read(&soft->dmaread_done))) {
- rv = -ERESTARTSYS;
- goto dmaread_exit;
- }
-
- rv = len;
- *off += len;
-
-dmaread_exit:
- mutex_unlock(&soft->dmareadlock);
-
- return rv;
-}
-
-static int mbcs_open(struct inode *ip, struct file *fp)
-{
- struct mbcs_soft *soft;
- int minor;
-
- mutex_lock(&mbcs_mutex);
- minor = iminor(ip);
-
- /* Nothing protects access to this list... */
- list_for_each_entry(soft, &soft_list, list) {
- if (soft->nasid == minor) {
- fp->private_data = soft->cxdev;
- mutex_unlock(&mbcs_mutex);
- return 0;
- }
- }
-
- mutex_unlock(&mbcs_mutex);
- return -ENODEV;
-}
-
-static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
-{
- struct cx_dev *cx_dev = fp->private_data;
- struct mbcs_soft *soft = cx_dev->soft;
- uint64_t hostAddr;
- int rv = 0;
-
- hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
- if (hostAddr == 0)
- return -ENOMEM;
-
- rv = do_mbcs_sram_dmawrite(soft, hostAddr, len, off);
- if (rv < 0)
- goto exit;
-
- if (copy_to_user(buf, (void *)hostAddr, len))
- rv = -EFAULT;
-
- exit:
- free_pages(hostAddr, get_order(len));
-
- return rv;
-}
-
-static ssize_t
-mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off)
-{
- struct cx_dev *cx_dev = fp->private_data;
- struct mbcs_soft *soft = cx_dev->soft;
- uint64_t hostAddr;
- int rv = 0;
-
- hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
- if (hostAddr == 0)
- return -ENOMEM;
-
- if (copy_from_user((void *)hostAddr, buf, len)) {
- rv = -EFAULT;
- goto exit;
- }
-
- rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off);
-
- exit:
- free_pages(hostAddr, get_order(len));
-
- return rv;
-}
-
-static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
-{
- return generic_file_llseek_size(filp, off, whence, MAX_LFS_FILESIZE,
- MBCS_SRAM_SIZE);
-}
-
-static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset)
-{
- uint64_t mmr_base;
-
- mmr_base = (uint64_t) (soft->mmr_base + offset);
-
- return mmr_base;
-}
-
-static void mbcs_debug_pioaddr_set(struct mbcs_soft *soft)
-{
- soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START);
-}
-
-static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft)
-{
- soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
-}
-
-static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
-{
- struct cx_dev *cx_dev = fp->private_data;
- struct mbcs_soft *soft = cx_dev->soft;
-
- if (vma->vm_pgoff != 0)
- return -EINVAL;
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- /* Remap-pfn-range will mark the range VM_IO */
- if (remap_pfn_range(vma,
- vma->vm_start,
- __pa(soft->gscr_addr) >> PAGE_SHIFT,
- PAGE_SIZE,
- vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
-}
-
-/**
- * mbcs_completion_intr_handler - Primary completion handler.
- * @irq: irq
- * @arg: soft struct for device
- *
- */
-static irqreturn_t
-mbcs_completion_intr_handler(int irq, void *arg)
-{
- struct mbcs_soft *soft = (struct mbcs_soft *)arg;
- void *mmr_base;
- union cm_status cm_status;
- union cm_control cm_control;
-
- mmr_base = soft->mmr_base;
- cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS);
-
- if (cm_status.rd_dma_done) {
- /* stop dma-read engine, clear status */
- cm_control.cm_control_reg =
- MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
- cm_control.rd_dma_clr = 1;
- MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
- cm_control.cm_control_reg);
- atomic_set(&soft->dmaread_done, 1);
- wake_up(&soft->dmaread_queue);
- }
- if (cm_status.wr_dma_done) {
- /* stop dma-write engine, clear status */
- cm_control.cm_control_reg =
- MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
- cm_control.wr_dma_clr = 1;
- MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
- cm_control.cm_control_reg);
- atomic_set(&soft->dmawrite_done, 1);
- wake_up(&soft->dmawrite_queue);
- }
- if (cm_status.alg_done) {
- /* clear status */
- cm_control.cm_control_reg =
- MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
- cm_control.alg_done_clr = 1;
- MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
- cm_control.cm_control_reg);
- atomic_set(&soft->algo_done, 1);
- wake_up(&soft->algo_queue);
- }
-
- return IRQ_HANDLED;
-}
-
-/**
- * mbcs_intr_alloc - Allocate interrupts.
- * @dev: device pointer
- *
- */
-static int mbcs_intr_alloc(struct cx_dev *dev)
-{
- struct sn_irq_info *sn_irq;
- struct mbcs_soft *soft;
- struct getdma *getdma;
- struct putdma *putdma;
- struct algoblock *algo;
-
- soft = dev->soft;
- getdma = &soft->getdma;
- putdma = &soft->putdma;
- algo = &soft->algo;
-
- soft->get_sn_irq = NULL;
- soft->put_sn_irq = NULL;
- soft->algo_sn_irq = NULL;
-
- sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
- if (sn_irq == NULL)
- return -EAGAIN;
- soft->get_sn_irq = sn_irq;
- getdma->intrHostDest = sn_irq->irq_xtalkaddr;
- getdma->intrVector = sn_irq->irq_irq;
- if (request_irq(sn_irq->irq_irq,
- (void *)mbcs_completion_intr_handler, IRQF_SHARED,
- "MBCS get intr", (void *)soft)) {
- tiocx_irq_free(soft->get_sn_irq);
- return -EAGAIN;
- }
-
- sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
- if (sn_irq == NULL) {
- free_irq(soft->get_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->get_sn_irq);
- return -EAGAIN;
- }
- soft->put_sn_irq = sn_irq;
- putdma->intrHostDest = sn_irq->irq_xtalkaddr;
- putdma->intrVector = sn_irq->irq_irq;
- if (request_irq(sn_irq->irq_irq,
- (void *)mbcs_completion_intr_handler, IRQF_SHARED,
- "MBCS put intr", (void *)soft)) {
- tiocx_irq_free(soft->put_sn_irq);
- free_irq(soft->get_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->get_sn_irq);
- return -EAGAIN;
- }
-
- sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
- if (sn_irq == NULL) {
- free_irq(soft->put_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->put_sn_irq);
- free_irq(soft->get_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->get_sn_irq);
- return -EAGAIN;
- }
- soft->algo_sn_irq = sn_irq;
- algo->intrHostDest = sn_irq->irq_xtalkaddr;
- algo->intrVector = sn_irq->irq_irq;
- if (request_irq(sn_irq->irq_irq,
- (void *)mbcs_completion_intr_handler, IRQF_SHARED,
- "MBCS algo intr", (void *)soft)) {
- tiocx_irq_free(soft->algo_sn_irq);
- free_irq(soft->put_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->put_sn_irq);
- free_irq(soft->get_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->get_sn_irq);
- return -EAGAIN;
- }
-
- return 0;
-}
-
-/**
- * mbcs_intr_dealloc - Remove interrupts.
- * @dev: device pointer
- *
- */
-static void mbcs_intr_dealloc(struct cx_dev *dev)
-{
- struct mbcs_soft *soft;
-
- soft = dev->soft;
-
- free_irq(soft->get_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->get_sn_irq);
- free_irq(soft->put_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->put_sn_irq);
- free_irq(soft->algo_sn_irq->irq_irq, soft);
- tiocx_irq_free(soft->algo_sn_irq);
-}
-
-static inline int mbcs_hw_init(struct mbcs_soft *soft)
-{
- void *mmr_base = soft->mmr_base;
- union cm_control cm_control;
- union cm_req_timeout cm_req_timeout;
- uint64_t err_stat;
-
- cm_req_timeout.cm_req_timeout_reg =
- MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT);
-
- cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK;
- MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT,
- cm_req_timeout.cm_req_timeout_reg);
-
- mbcs_gscr_pioaddr_set(soft);
- mbcs_debug_pioaddr_set(soft);
-
- /* clear errors */
- err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT);
- MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat);
- MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1);
-
- /* enable interrupts */
- /* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */
- MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL);
-
- /* arm status regs and clear engines */
- cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
- cm_control.rearm_stat_regs = 1;
- cm_control.alg_clr = 1;
- cm_control.wr_dma_clr = 1;
- cm_control.rd_dma_clr = 1;
-
- MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
-
- return 0;
-}
-
-static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct cx_dev *cx_dev = to_cx_dev(dev);
- struct mbcs_soft *soft = cx_dev->soft;
- uint64_t debug0;
-
- /*
- * By convention, the first debug register contains the
- * algorithm number and revision.
- */
- debug0 = *(uint64_t *) soft->debug_addr;
-
- return sprintf(buf, "0x%x 0x%x\n",
- upper_32_bits(debug0), lower_32_bits(debug0));
-}
-
-static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- int n;
- struct cx_dev *cx_dev = to_cx_dev(dev);
- struct mbcs_soft *soft = cx_dev->soft;
-
- if (count <= 0)
- return 0;
-
- n = simple_strtoul(buf, NULL, 0);
-
- if (n == 1) {
- mbcs_algo_start(soft);
- if (wait_event_interruptible(soft->algo_queue,
- atomic_read(&soft->algo_done)))
- return -ERESTARTSYS;
- }
-
- return count;
-}
-
-DEVICE_ATTR(algo, 0644, show_algo, store_algo);
-
-/**
- * mbcs_probe - Initialize for device
- * @dev: device pointer
- * @device_id: id table pointer
- *
- */
-static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
-{
- struct mbcs_soft *soft;
-
- dev->soft = NULL;
-
- soft = kzalloc(sizeof(struct mbcs_soft), GFP_KERNEL);
- if (soft == NULL)
- return -ENOMEM;
-
- soft->nasid = dev->cx_id.nasid;
- list_add(&soft->list, &soft_list);
- soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid);
- dev->soft = soft;
- soft->cxdev = dev;
-
- init_waitqueue_head(&soft->dmawrite_queue);
- init_waitqueue_head(&soft->dmaread_queue);
- init_waitqueue_head(&soft->algo_queue);
-
- mutex_init(&soft->dmawritelock);
- mutex_init(&soft->dmareadlock);
- mutex_init(&soft->algolock);
-
- mbcs_getdma_init(&soft->getdma);
- mbcs_putdma_init(&soft->putdma);
- mbcs_algo_init(&soft->algo);
-
- mbcs_hw_init(soft);
-
- /* Allocate interrupts */
- mbcs_intr_alloc(dev);
-
- device_create_file(&dev->dev, &dev_attr_algo);
-
- return 0;
-}
-
-static int mbcs_remove(struct cx_dev *dev)
-{
- if (dev->soft) {
- mbcs_intr_dealloc(dev);
- kfree(dev->soft);
- }
-
- device_remove_file(&dev->dev, &dev_attr_algo);
-
- return 0;
-}
-
-static const struct cx_device_id mbcs_id_table[] = {
- {
- .part_num = MBCS_PART_NUM,
- .mfg_num = MBCS_MFG_NUM,
- },
- {
- .part_num = MBCS_PART_NUM_ALG0,
- .mfg_num = MBCS_MFG_NUM,
- },
- {0, 0}
-};
-
-MODULE_DEVICE_TABLE(cx, mbcs_id_table);
-
-static struct cx_drv mbcs_driver = {
- .name = DEVICE_NAME,
- .id_table = mbcs_id_table,
- .probe = mbcs_probe,
- .remove = mbcs_remove,
-};
-
-static void __exit mbcs_exit(void)
-{
- unregister_chrdev(mbcs_major, DEVICE_NAME);
- cx_driver_unregister(&mbcs_driver);
-}
-
-static int __init mbcs_init(void)
-{
- int rv;
-
- if (!ia64_platform_is("sn2"))
- return -ENODEV;
-
- // Put driver into chrdevs[]. Get major number.
- rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops);
- if (rv < 0) {
- DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv);
- return rv;
- }
- mbcs_major = rv;
-
- return cx_driver_register(&mbcs_driver);
-}
-
-module_init(mbcs_init);
-module_exit(mbcs_exit);
-
-MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
-MODULE_DESCRIPTION("Driver for MOATB Core Services");
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h
deleted file mode 100644
index 1a36884c48b5..000000000000
--- a/drivers/char/mbcs.h
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved.
- */
-
-#ifndef __MBCS_H__
-#define __MBCS_H__
-
-/*
- * General macros
- */
-#define MB (1024*1024)
-#define MB2 (2*MB)
-#define MB4 (4*MB)
-#define MB6 (6*MB)
-
-/*
- * Offsets and masks
- */
-#define MBCS_CM_ID 0x0000 /* Identification */
-#define MBCS_CM_STATUS 0x0008 /* Status */
-#define MBCS_CM_ERROR_DETAIL1 0x0010 /* Error Detail1 */
-#define MBCS_CM_ERROR_DETAIL2 0x0018 /* Error Detail2 */
-#define MBCS_CM_CONTROL 0x0020 /* Control */
-#define MBCS_CM_REQ_TOUT 0x0028 /* Request Time-out */
-#define MBCS_CM_ERR_INT_DEST 0x0038 /* Error Interrupt Destination */
-#define MBCS_CM_TARG_FL 0x0050 /* Target Flush */
-#define MBCS_CM_ERR_STAT 0x0060 /* Error Status */
-#define MBCS_CM_CLR_ERR_STAT 0x0068 /* Clear Error Status */
-#define MBCS_CM_ERR_INT_EN 0x0070 /* Error Interrupt Enable */
-#define MBCS_RD_DMA_SYS_ADDR 0x0100 /* Read DMA System Address */
-#define MBCS_RD_DMA_LOC_ADDR 0x0108 /* Read DMA Local Address */
-#define MBCS_RD_DMA_CTRL 0x0110 /* Read DMA Control */
-#define MBCS_RD_DMA_AMO_DEST 0x0118 /* Read DMA AMO Destination */
-#define MBCS_RD_DMA_INT_DEST 0x0120 /* Read DMA Interrupt Destination */
-#define MBCS_RD_DMA_AUX_STAT 0x0130 /* Read DMA Auxiliary Status */
-#define MBCS_WR_DMA_SYS_ADDR 0x0200 /* Write DMA System Address */
-#define MBCS_WR_DMA_LOC_ADDR 0x0208 /* Write DMA Local Address */
-#define MBCS_WR_DMA_CTRL 0x0210 /* Write DMA Control */
-#define MBCS_WR_DMA_AMO_DEST 0x0218 /* Write DMA AMO Destination */
-#define MBCS_WR_DMA_INT_DEST 0x0220 /* Write DMA Interrupt Destination */
-#define MBCS_WR_DMA_AUX_STAT 0x0230 /* Write DMA Auxiliary Status */
-#define MBCS_ALG_AMO_DEST 0x0300 /* Algorithm AMO Destination */
-#define MBCS_ALG_INT_DEST 0x0308 /* Algorithm Interrupt Destination */
-#define MBCS_ALG_OFFSETS 0x0310
-#define MBCS_ALG_STEP 0x0318 /* Algorithm Step */
-
-#define MBCS_GSCR_START 0x0000000
-#define MBCS_DEBUG_START 0x0100000
-#define MBCS_RAM0_START 0x0200000
-#define MBCS_RAM1_START 0x0400000
-#define MBCS_RAM2_START 0x0600000
-
-#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL
-//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL
-
-#define MBCS_SRAM_SIZE (1024*1024)
-#define MBCS_CACHELINE_SIZE 128
-
-/*
- * MMR get's and put's
- */
-#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset))
-#define MBCS_MMR_SET(mmr_base, offset, value) { \
- uint64_t *mbcs_mmr_set_u64p, readback; \
- mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset); \
- *mbcs_mmr_set_u64p = value; \
- readback = *mbcs_mmr_set_u64p; \
-}
-#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset)
-#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0)
-
-/*
- * MBCS mmr structures
- */
-union cm_id {
- uint64_t cm_id_reg;
- struct {
- uint64_t always_one:1, // 0
- mfg_id:11, // 11:1
- part_num:16, // 27:12
- bitstream_rev:8, // 35:28
- :28; // 63:36
- };
-};
-
-union cm_status {
- uint64_t cm_status_reg;
- struct {
- uint64_t pending_reads:8, // 7:0
- pending_writes:8, // 15:8
- ice_rsp_credits:8, // 23:16
- ice_req_credits:8, // 31:24
- cm_req_credits:8, // 39:32
- :1, // 40
- rd_dma_in_progress:1, // 41
- rd_dma_done:1, // 42
- :1, // 43
- wr_dma_in_progress:1, // 44
- wr_dma_done:1, // 45
- alg_waiting:1, // 46
- alg_pipe_running:1, // 47
- alg_done:1, // 48
- :3, // 51:49
- pending_int_reqs:8, // 59:52
- :3, // 62:60
- alg_half_speed_sel:1; // 63
- };
-};
-
-union cm_error_detail1 {
- uint64_t cm_error_detail1_reg;
- struct {
- uint64_t packet_type:4, // 3:0
- source_id:2, // 5:4
- data_size:2, // 7:6
- tnum:8, // 15:8
- byte_enable:8, // 23:16
- gfx_cred:8, // 31:24
- read_type:2, // 33:32
- pio_or_memory:1, // 34
- head_cw_error:1, // 35
- :12, // 47:36
- head_error_bit:1, // 48
- data_error_bit:1, // 49
- :13, // 62:50
- valid:1; // 63
- };
-};
-
-union cm_error_detail2 {
- uint64_t cm_error_detail2_reg;
- struct {
- uint64_t address:56, // 55:0
- :8; // 63:56
- };
-};
-
-union cm_control {
- uint64_t cm_control_reg;
- struct {
- uint64_t cm_id:2, // 1:0
- :2, // 3:2
- max_trans:5, // 8:4
- :3, // 11:9
- address_mode:1, // 12
- :7, // 19:13
- credit_limit:8, // 27:20
- :5, // 32:28
- rearm_stat_regs:1, // 33
- prescalar_byp:1, // 34
- force_gap_war:1, // 35
- rd_dma_go:1, // 36
- wr_dma_go:1, // 37
- alg_go:1, // 38
- rd_dma_clr:1, // 39
- wr_dma_clr:1, // 40
- alg_clr:1, // 41
- :2, // 43:42
- alg_wait_step:1, // 44
- alg_done_amo_en:1, // 45
- alg_done_int_en:1, // 46
- :1, // 47
- alg_sram0_locked:1, // 48
- alg_sram1_locked:1, // 49
- alg_sram2_locked:1, // 50
- alg_done_clr:1, // 51
- :12; // 63:52
- };
-};
-
-union cm_req_timeout {
- uint64_t cm_req_timeout_reg;
- struct {
- uint64_t time_out:24, // 23:0
- :40; // 63:24
- };
-};
-
-union intr_dest {
- uint64_t intr_dest_reg;
- struct {
- uint64_t address:56, // 55:0
- int_vector:8; // 63:56
- };
-};
-
-union cm_error_status {
- uint64_t cm_error_status_reg;
- struct {
- uint64_t ecc_sbe:1, // 0
- ecc_mbe:1, // 1
- unsupported_req:1, // 2
- unexpected_rsp:1, // 3
- bad_length:1, // 4
- bad_datavalid:1, // 5
- buffer_overflow:1, // 6
- request_timeout:1, // 7
- :8, // 15:8
- head_inv_data_size:1, // 16
- rsp_pactype_inv:1, // 17
- head_sb_err:1, // 18
- missing_head:1, // 19
- head_inv_rd_type:1, // 20
- head_cmd_err_bit:1, // 21
- req_addr_align_inv:1, // 22
- pio_req_addr_inv:1, // 23
- req_range_dsize_inv:1, // 24
- early_term:1, // 25
- early_tail:1, // 26
- missing_tail:1, // 27
- data_flit_sb_err:1, // 28
- cm2hcm_req_cred_of:1, // 29
- cm2hcm_rsp_cred_of:1, // 30
- rx_bad_didn:1, // 31
- rd_dma_err_rsp:1, // 32
- rd_dma_tnum_tout:1, // 33
- rd_dma_multi_tnum_tou:1, // 34
- wr_dma_err_rsp:1, // 35
- wr_dma_tnum_tout:1, // 36
- wr_dma_multi_tnum_tou:1, // 37
- alg_data_overflow:1, // 38
- alg_data_underflow:1, // 39
- ram0_access_conflict:1, // 40
- ram1_access_conflict:1, // 41
- ram2_access_conflict:1, // 42
- ram0_perr:1, // 43
- ram1_perr:1, // 44
- ram2_perr:1, // 45
- int_gen_rsp_err:1, // 46
- int_gen_tnum_tout:1, // 47
- rd_dma_prog_err:1, // 48
- wr_dma_prog_err:1, // 49
- :14; // 63:50
- };
-};
-
-union cm_clr_error_status {
- uint64_t cm_clr_error_status_reg;
- struct {
- uint64_t clr_ecc_sbe:1, // 0
- clr_ecc_mbe:1, // 1
- clr_unsupported_req:1, // 2
- clr_unexpected_rsp:1, // 3
- clr_bad_length:1, // 4
- clr_bad_datavalid:1, // 5
- clr_buffer_overflow:1, // 6
- clr_request_timeout:1, // 7
- :8, // 15:8
- clr_head_inv_data_siz:1, // 16
- clr_rsp_pactype_inv:1, // 17
- clr_head_sb_err:1, // 18
- clr_missing_head:1, // 19
- clr_head_inv_rd_type:1, // 20
- clr_head_cmd_err_bit:1, // 21
- clr_req_addr_align_in:1, // 22
- clr_pio_req_addr_inv:1, // 23
- clr_req_range_dsize_i:1, // 24
- clr_early_term:1, // 25
- clr_early_tail:1, // 26
- clr_missing_tail:1, // 27
- clr_data_flit_sb_err:1, // 28
- clr_cm2hcm_req_cred_o:1, // 29
- clr_cm2hcm_rsp_cred_o:1, // 30
- clr_rx_bad_didn:1, // 31
- clr_rd_dma_err_rsp:1, // 32
- clr_rd_dma_tnum_tout:1, // 33
- clr_rd_dma_multi_tnum:1, // 34
- clr_wr_dma_err_rsp:1, // 35
- clr_wr_dma_tnum_tout:1, // 36
- clr_wr_dma_multi_tnum:1, // 37
- clr_alg_data_overflow:1, // 38
- clr_alg_data_underflo:1, // 39
- clr_ram0_access_confl:1, // 40
- clr_ram1_access_confl:1, // 41
- clr_ram2_access_confl:1, // 42
- clr_ram0_perr:1, // 43
- clr_ram1_perr:1, // 44
- clr_ram2_perr:1, // 45
- clr_int_gen_rsp_err:1, // 46
- clr_int_gen_tnum_tout:1, // 47
- clr_rd_dma_prog_err:1, // 48
- clr_wr_dma_prog_err:1, // 49
- :14; // 63:50
- };
-};
-
-union cm_error_intr_enable {
- uint64_t cm_error_intr_enable_reg;
- struct {
- uint64_t int_en_ecc_sbe:1, // 0
- int_en_ecc_mbe:1, // 1
- int_en_unsupported_re:1, // 2
- int_en_unexpected_rsp:1, // 3
- int_en_bad_length:1, // 4
- int_en_bad_datavalid:1, // 5
- int_en_buffer_overflo:1, // 6
- int_en_request_timeou:1, // 7
- :8, // 15:8
- int_en_head_inv_data_:1, // 16
- int_en_rsp_pactype_in:1, // 17
- int_en_head_sb_err:1, // 18
- int_en_missing_head:1, // 19
- int_en_head_inv_rd_ty:1, // 20
- int_en_head_cmd_err_b:1, // 21
- int_en_req_addr_align:1, // 22
- int_en_pio_req_addr_i:1, // 23
- int_en_req_range_dsiz:1, // 24
- int_en_early_term:1, // 25
- int_en_early_tail:1, // 26
- int_en_missing_tail:1, // 27
- int_en_data_flit_sb_e:1, // 28
- int_en_cm2hcm_req_cre:1, // 29
- int_en_cm2hcm_rsp_cre:1, // 30
- int_en_rx_bad_didn:1, // 31
- int_en_rd_dma_err_rsp:1, // 32
- int_en_rd_dma_tnum_to:1, // 33
- int_en_rd_dma_multi_t:1, // 34
- int_en_wr_dma_err_rsp:1, // 35
- int_en_wr_dma_tnum_to:1, // 36
- int_en_wr_dma_multi_t:1, // 37
- int_en_alg_data_overf:1, // 38
- int_en_alg_data_under:1, // 39
- int_en_ram0_access_co:1, // 40
- int_en_ram1_access_co:1, // 41
- int_en_ram2_access_co:1, // 42
- int_en_ram0_perr:1, // 43
- int_en_ram1_perr:1, // 44
- int_en_ram2_perr:1, // 45
- int_en_int_gen_rsp_er:1, // 46
- int_en_int_gen_tnum_t:1, // 47
- int_en_rd_dma_prog_er:1, // 48
- int_en_wr_dma_prog_er:1, // 49
- :14; // 63:50
- };
-};
-
-struct cm_mmr {
- union cm_id id;
- union cm_status status;
- union cm_error_detail1 err_detail1;
- union cm_error_detail2 err_detail2;
- union cm_control control;
- union cm_req_timeout req_timeout;
- uint64_t reserved1[1];
- union intr_dest int_dest;
- uint64_t reserved2[2];
- uint64_t targ_flush;
- uint64_t reserved3[1];
- union cm_error_status err_status;
- union cm_clr_error_status clr_err_status;
- union cm_error_intr_enable int_enable;
-};
-
-union dma_hostaddr {
- uint64_t dma_hostaddr_reg;
- struct {
- uint64_t dma_sys_addr:56, // 55:0
- :8; // 63:56
- };
-};
-
-union dma_localaddr {
- uint64_t dma_localaddr_reg;
- struct {
- uint64_t dma_ram_addr:21, // 20:0
- dma_ram_sel:2, // 22:21
- :41; // 63:23
- };
-};
-
-union dma_control {
- uint64_t dma_control_reg;
- struct {
- uint64_t dma_op_length:16, // 15:0
- :18, // 33:16
- done_amo_en:1, // 34
- done_int_en:1, // 35
- :1, // 36
- pio_mem_n:1, // 37
- :26; // 63:38
- };
-};
-
-union dma_amo_dest {
- uint64_t dma_amo_dest_reg;
- struct {
- uint64_t dma_amo_sys_addr:56, // 55:0
- dma_amo_mod_type:3, // 58:56
- :5; // 63:59
- };
-};
-
-union rdma_aux_status {
- uint64_t rdma_aux_status_reg;
- struct {
- uint64_t op_num_pacs_left:17, // 16:0
- :5, // 21:17
- lrsp_buff_empty:1, // 22
- :17, // 39:23
- pending_reqs_left:6, // 45:40
- :18; // 63:46
- };
-};
-
-struct rdma_mmr {
- union dma_hostaddr host_addr;
- union dma_localaddr local_addr;
- union dma_control control;
- union dma_amo_dest amo_dest;
- union intr_dest intr_dest;
- union rdma_aux_status aux_status;
-};
-
-union wdma_aux_status {
- uint64_t wdma_aux_status_reg;
- struct {
- uint64_t op_num_pacs_left:17, // 16:0
- :4, // 20:17
- lreq_buff_empty:1, // 21
- :18, // 39:22
- pending_reqs_left:6, // 45:40
- :18; // 63:46
- };
-};
-
-struct wdma_mmr {
- union dma_hostaddr host_addr;
- union dma_localaddr local_addr;
- union dma_control control;
- union dma_amo_dest amo_dest;
- union intr_dest intr_dest;
- union wdma_aux_status aux_status;
-};
-
-union algo_step {
- uint64_t algo_step_reg;
- struct {
- uint64_t alg_step_cnt:16, // 15:0
- :48; // 63:16
- };
-};
-
-struct algo_mmr {
- union dma_amo_dest amo_dest;
- union intr_dest intr_dest;
- union {
- uint64_t algo_offset_reg;
- struct {
- uint64_t sram0_offset:7, // 6:0
- reserved0:1, // 7
- sram1_offset:7, // 14:8
- reserved1:1, // 15
- sram2_offset:7, // 22:16
- reserved2:14; // 63:23
- };
- } sram_offset;
- union algo_step step;
-};
-
-struct mbcs_mmr {
- struct cm_mmr cm;
- uint64_t reserved1[17];
- struct rdma_mmr rdDma;
- uint64_t reserved2[25];
- struct wdma_mmr wrDma;
- uint64_t reserved3[25];
- struct algo_mmr algo;
- uint64_t reserved4[156];
-};
-
-/*
- * defines
- */
-#define DEVICE_NAME "mbcs"
-#define MBCS_PART_NUM 0xfff0
-#define MBCS_PART_NUM_ALG0 0xf001
-#define MBCS_MFG_NUM 0x1
-
-struct algoblock {
- uint64_t amoHostDest;
- uint64_t amoModType;
- uint64_t intrHostDest;
- uint64_t intrVector;
- uint64_t algoStepCount;
-};
-
-struct getdma {
- uint64_t hostAddr;
- uint64_t localAddr;
- uint64_t bytes;
- uint64_t DoneAmoEnable;
- uint64_t DoneIntEnable;
- uint64_t peerIO;
- uint64_t amoHostDest;
- uint64_t amoModType;
- uint64_t intrHostDest;
- uint64_t intrVector;
-};
-
-struct putdma {
- uint64_t hostAddr;
- uint64_t localAddr;
- uint64_t bytes;
- uint64_t DoneAmoEnable;
- uint64_t DoneIntEnable;
- uint64_t peerIO;
- uint64_t amoHostDest;
- uint64_t amoModType;
- uint64_t intrHostDest;
- uint64_t intrVector;
-};
-
-struct mbcs_soft {
- struct list_head list;
- struct cx_dev *cxdev;
- int major;
- int nasid;
- void *mmr_base;
- wait_queue_head_t dmawrite_queue;
- wait_queue_head_t dmaread_queue;
- wait_queue_head_t algo_queue;
- struct sn_irq_info *get_sn_irq;
- struct sn_irq_info *put_sn_irq;
- struct sn_irq_info *algo_sn_irq;
- struct getdma getdma;
- struct putdma putdma;
- struct algoblock algo;
- uint64_t gscr_addr; // pio addr
- uint64_t ram0_addr; // pio addr
- uint64_t ram1_addr; // pio addr
- uint64_t ram2_addr; // pio addr
- uint64_t debug_addr; // pio addr
- atomic_t dmawrite_done;
- atomic_t dmaread_done;
- atomic_t algo_done;
- struct mutex dmawritelock;
- struct mutex dmareadlock;
- struct mutex algolock;
-};
-
-static int mbcs_open(struct inode *ip, struct file *fp);
-static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
- loff_t * off);
-static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
- loff_t * off);
-static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
-static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
-
-#endif // __MBCS_H__
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index e75c9df7c2d8..a9d9f074fbd6 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -9,11 +9,8 @@
*
* This driver exports the SN special memory (mspec) facility to user
* processes.
- * There are three types of memory made available thru this driver:
- * fetchops, uncached and cached.
- *
- * Fetchops are atomic memory operations that are implemented in the
- * memory controller on SGI SN hardware.
+ * There are two types of memory made available thru this driver:
+ * uncached and cached.
*
* Uncached are used for memory write combining feature of the ia64
* cpu.
@@ -46,16 +43,8 @@
#include <linux/atomic.h>
#include <asm/tlbflush.h>
#include <asm/uncached.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/mspec.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/io.h>
-#include <asm/sn/bte.h>
-#include <asm/sn/shubio.h>
-#define FETCHOP_ID "SGI Fetchop,"
#define CACHED_ID "Cached,"
#define UNCACHED_ID "Uncached"
#define REVISION "4.0"
@@ -65,17 +54,10 @@
* Page types allocated by the device.
*/
enum mspec_page_type {
- MSPEC_FETCHOP = 1,
- MSPEC_CACHED,
+ MSPEC_CACHED = 2,
MSPEC_UNCACHED
};
-#ifdef CONFIG_SGI_SN
-static int is_sn2;
-#else
-#define is_sn2 0
-#endif
-
/*
* One of these structures is allocated when an mspec region is mmaped. The
* structure is pointed to by the vma->vm_private_data field in the vma struct.
@@ -96,39 +78,6 @@ struct vma_data {
unsigned long maddr[0]; /* Array of MSPEC addresses. */
};
-/* used on shub2 to clear FOP cache in the HUB */
-static unsigned long scratch_page[MAX_NUMNODES];
-#define SH2_AMO_CACHE_ENTRIES 4
-
-static inline int
-mspec_zero_block(unsigned long addr, int len)
-{
- int status;
-
- if (is_sn2) {
- if (is_shub2()) {
- int nid;
- void *p;
- int i;
-
- nid = nasid_to_cnodeid(get_node_number(__pa(addr)));
- p = (void *)TO_AMO(scratch_page[nid]);
-
- for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) {
- FETCHOP_LOAD_OP(p, FETCHOP_LOAD);
- p += FETCHOP_VAR_SIZE;
- }
- }
-
- status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len,
- BTE_WACQUIRE | BTE_ZERO_FILL, NULL);
- } else {
- memset((char *) addr, 0, len);
- status = 0;
- }
- return status;
-}
-
/*
* mspec_open
*
@@ -173,11 +122,8 @@ mspec_close(struct vm_area_struct *vma)
*/
my_page = vdata->maddr[index];
vdata->maddr[index] = 0;
- if (!mspec_zero_block(my_page, PAGE_SIZE))
- uncached_free_page(my_page, 1);
- else
- printk(KERN_WARNING "mspec_close(): "
- "failed to zero page %ld\n", my_page);
+ memset((char *)my_page, 0, PAGE_SIZE);
+ uncached_free_page(my_page, 1);
}
kvfree(vdata);
@@ -213,11 +159,7 @@ mspec_fault(struct vm_fault *vmf)
spin_unlock(&vdata->lock);
}
- if (vdata->type == MSPEC_FETCHOP)
- paddr = TO_AMO(maddr);
- else
- paddr = maddr & ~__IA64_UNCACHED_OFFSET;
-
+ paddr = maddr & ~__IA64_UNCACHED_OFFSET;
pfn = paddr >> PAGE_SHIFT;
return vmf_insert_pfn(vmf->vma, vmf->address, pfn);
@@ -269,7 +211,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
vma->vm_private_data = vdata;
vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
- if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
+ if (vdata->type == MSPEC_UNCACHED)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &mspec_vm_ops;
@@ -277,12 +219,6 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
}
static int
-fetchop_mmap(struct file *file, struct vm_area_struct *vma)
-{
- return mspec_mmap(file, vma, MSPEC_FETCHOP);
-}
-
-static int
cached_mmap(struct file *file, struct vm_area_struct *vma)
{
return mspec_mmap(file, vma, MSPEC_CACHED);
@@ -294,18 +230,6 @@ uncached_mmap(struct file *file, struct vm_area_struct *vma)
return mspec_mmap(file, vma, MSPEC_UNCACHED);
}
-static const struct file_operations fetchop_fops = {
- .owner = THIS_MODULE,
- .mmap = fetchop_mmap,
- .llseek = noop_llseek,
-};
-
-static struct miscdevice fetchop_miscdev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "sgi_fetchop",
- .fops = &fetchop_fops
-};
-
static const struct file_operations cached_fops = {
.owner = THIS_MODULE,
.mmap = cached_mmap,
@@ -339,89 +263,32 @@ static int __init
mspec_init(void)
{
int ret;
- int nid;
-
- /*
- * The fetchop device only works on SN2 hardware, uncached and cached
- * memory drivers should both be valid on all ia64 hardware
- */
-#ifdef CONFIG_SGI_SN
- if (ia64_platform_is("sn2")) {
- is_sn2 = 1;
- if (is_shub2()) {
- ret = -ENOMEM;
- for_each_node_state(nid, N_ONLINE) {
- int actual_nid;
- int nasid;
- unsigned long phys;
-
- scratch_page[nid] = uncached_alloc_page(nid, 1);
- if (scratch_page[nid] == 0)
- goto free_scratch_pages;
- phys = __pa(scratch_page[nid]);
- nasid = get_node_number(phys);
- actual_nid = nasid_to_cnodeid(nasid);
- if (actual_nid != nid)
- goto free_scratch_pages;
- }
- }
- ret = misc_register(&fetchop_miscdev);
- if (ret) {
- printk(KERN_ERR
- "%s: failed to register device %i\n",
- FETCHOP_ID, ret);
- goto free_scratch_pages;
- }
- }
-#endif
ret = misc_register(&cached_miscdev);
if (ret) {
printk(KERN_ERR "%s: failed to register device %i\n",
CACHED_ID, ret);
- if (is_sn2)
- misc_deregister(&fetchop_miscdev);
- goto free_scratch_pages;
+ return ret;
}
ret = misc_register(&uncached_miscdev);
if (ret) {
printk(KERN_ERR "%s: failed to register device %i\n",
UNCACHED_ID, ret);
misc_deregister(&cached_miscdev);
- if (is_sn2)
- misc_deregister(&fetchop_miscdev);
- goto free_scratch_pages;
+ return ret;
}
- printk(KERN_INFO "%s %s initialized devices: %s %s %s\n",
- MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "",
- CACHED_ID, UNCACHED_ID);
+ printk(KERN_INFO "%s %s initialized devices: %s %s\n",
+ MSPEC_BASENAME, REVISION, CACHED_ID, UNCACHED_ID);
return 0;
-
- free_scratch_pages:
- for_each_node(nid) {
- if (scratch_page[nid] != 0)
- uncached_free_page(scratch_page[nid], 1);
- }
- return ret;
}
static void __exit
mspec_exit(void)
{
- int nid;
-
misc_deregister(&uncached_miscdev);
misc_deregister(&cached_miscdev);
- if (is_sn2) {
- misc_deregister(&fetchop_miscdev);
-
- for_each_node(nid) {
- if (scratch_page[nid] != 0)
- uncached_free_page(scratch_page[nid], 1);
- }
- }
}
module_init(mspec_init);
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
deleted file mode 100644
index 5918ea7499bb..000000000000
--- a/drivers/char/snsc.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * SN Platform system controller communication support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004, 2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * System controller communication driver
- *
- * This driver allows a user process to communicate with the system
- * controller (a.k.a. "IRouter") network in an SGI SN system.
- */
-
-#include <linux/interrupt.h>
-#include <linux/sched/signal.h>
-#include <linux/device.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/module.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/nodepda.h>
-#include "snsc.h"
-
-#define SYSCTL_BASENAME "snsc"
-
-#define SCDRV_BUFSZ 2048
-#define SCDRV_TIMEOUT 1000
-
-static DEFINE_MUTEX(scdrv_mutex);
-static irqreturn_t
-scdrv_interrupt(int irq, void *subch_data)
-{
- struct subch_data_s *sd = subch_data;
- unsigned long flags;
- int status;
-
- spin_lock_irqsave(&sd->sd_rlock, flags);
- spin_lock(&sd->sd_wlock);
- status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
-
- if (status > 0) {
- if (status & SAL_IROUTER_INTR_RECV) {
- wake_up(&sd->sd_rq);
- }
- if (status & SAL_IROUTER_INTR_XMIT) {
- ia64_sn_irtr_intr_disable
- (sd->sd_nasid, sd->sd_subch,
- SAL_IROUTER_INTR_XMIT);
- wake_up(&sd->sd_wq);
- }
- }
- spin_unlock(&sd->sd_wlock);
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
- return IRQ_HANDLED;
-}
-
-/*
- * scdrv_open
- *
- * Reserve a subchannel for system controller communication.
- */
-
-static int
-scdrv_open(struct inode *inode, struct file *file)
-{
- struct sysctl_data_s *scd;
- struct subch_data_s *sd;
- int rv;
-
- /* look up device info for this device file */
- scd = container_of(inode->i_cdev, struct sysctl_data_s, scd_cdev);
-
- /* allocate memory for subchannel data */
- sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
- if (sd == NULL) {
- printk("%s: couldn't allocate subchannel data\n",
- __func__);
- return -ENOMEM;
- }
-
- /* initialize subch_data_s fields */
- sd->sd_nasid = scd->scd_nasid;
- sd->sd_subch = ia64_sn_irtr_open(scd->scd_nasid);
-
- if (sd->sd_subch < 0) {
- kfree(sd);
- printk("%s: couldn't allocate subchannel\n", __func__);
- return -EBUSY;
- }
-
- spin_lock_init(&sd->sd_rlock);
- spin_lock_init(&sd->sd_wlock);
- init_waitqueue_head(&sd->sd_rq);
- init_waitqueue_head(&sd->sd_wq);
- sema_init(&sd->sd_rbs, 1);
- sema_init(&sd->sd_wbs, 1);
-
- file->private_data = sd;
-
- /* hook this subchannel up to the system controller interrupt */
- mutex_lock(&scdrv_mutex);
- rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt,
- IRQF_SHARED, SYSCTL_BASENAME, sd);
- if (rv) {
- ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
- kfree(sd);
- printk("%s: irq request failed (%d)\n", __func__, rv);
- mutex_unlock(&scdrv_mutex);
- return -EBUSY;
- }
- mutex_unlock(&scdrv_mutex);
- return 0;
-}
-
-/*
- * scdrv_release
- *
- * Release a previously-reserved subchannel.
- */
-
-static int
-scdrv_release(struct inode *inode, struct file *file)
-{
- struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
- int rv;
-
- /* free the interrupt */
- free_irq(SGI_UART_VECTOR, sd);
-
- /* ask SAL to close the subchannel */
- rv = ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
-
- kfree(sd);
- return rv;
-}
-
-/*
- * scdrv_read
- *
- * Called to read bytes from the open IRouter pipe.
- *
- */
-
-static inline int
-read_status_check(struct subch_data_s *sd, int *len)
-{
- return ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch, sd->sd_rb, len);
-}
-
-static ssize_t
-scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
-{
- int status;
- int len;
- unsigned long flags;
- struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
-
- /* try to get control of the read buffer */
- if (down_trylock(&sd->sd_rbs)) {
- /* somebody else has it now;
- * if we're non-blocking, then exit...
- */
- if (file->f_flags & O_NONBLOCK) {
- return -EAGAIN;
- }
- /* ...or if we want to block, then do so here */
- if (down_interruptible(&sd->sd_rbs)) {
- /* something went wrong with wait */
- return -ERESTARTSYS;
- }
- }
-
- /* anything to read? */
- len = CHUNKSIZE;
- spin_lock_irqsave(&sd->sd_rlock, flags);
- status = read_status_check(sd, &len);
-
- /* if not, and we're blocking I/O, loop */
- while (status < 0) {
- DECLARE_WAITQUEUE(wait, current);
-
- if (file->f_flags & O_NONBLOCK) {
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
- up(&sd->sd_rbs);
- return -EAGAIN;
- }
-
- len = CHUNKSIZE;
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&sd->sd_rq, &wait);
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
-
- schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
-
- remove_wait_queue(&sd->sd_rq, &wait);
- if (signal_pending(current)) {
- /* wait was interrupted */
- up(&sd->sd_rbs);
- return -ERESTARTSYS;
- }
-
- spin_lock_irqsave(&sd->sd_rlock, flags);
- status = read_status_check(sd, &len);
- }
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
-
- if (len > 0) {
- /* we read something in the last read_status_check(); copy
- * it out to user space
- */
- if (count < len) {
- pr_debug("%s: only accepting %d of %d bytes\n",
- __func__, (int) count, len);
- }
- len = min((int) count, len);
- if (copy_to_user(buf, sd->sd_rb, len))
- len = -EFAULT;
- }
-
- /* release the read buffer and wake anyone who might be
- * waiting for it
- */
- up(&sd->sd_rbs);
-
- /* return the number of characters read in */
- return len;
-}
-
-/*
- * scdrv_write
- *
- * Writes a chunk of an IRouter packet (or other system controller data)
- * to the system controller.
- *
- */
-static inline int
-write_status_check(struct subch_data_s *sd, int count)
-{
- return ia64_sn_irtr_send(sd->sd_nasid, sd->sd_subch, sd->sd_wb, count);
-}
-
-static ssize_t
-scdrv_write(struct file *file, const char __user *buf,
- size_t count, loff_t *f_pos)
-{
- unsigned long flags;
- int status;
- struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
-
- /* try to get control of the write buffer */
- if (down_trylock(&sd->sd_wbs)) {
- /* somebody else has it now;
- * if we're non-blocking, then exit...
- */
- if (file->f_flags & O_NONBLOCK) {
- return -EAGAIN;
- }
- /* ...or if we want to block, then do so here */
- if (down_interruptible(&sd->sd_wbs)) {
- /* something went wrong with wait */
- return -ERESTARTSYS;
- }
- }
-
- count = min((int) count, CHUNKSIZE);
- if (copy_from_user(sd->sd_wb, buf, count)) {
- up(&sd->sd_wbs);
- return -EFAULT;
- }
-
- /* try to send the buffer */
- spin_lock_irqsave(&sd->sd_wlock, flags);
- status = write_status_check(sd, count);
-
- /* if we failed, and we want to block, then loop */
- while (status <= 0) {
- DECLARE_WAITQUEUE(wait, current);
-
- if (file->f_flags & O_NONBLOCK) {
- spin_unlock_irqrestore(&sd->sd_wlock, flags);
- up(&sd->sd_wbs);
- return -EAGAIN;
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&sd->sd_wq, &wait);
- spin_unlock_irqrestore(&sd->sd_wlock, flags);
-
- schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
-
- remove_wait_queue(&sd->sd_wq, &wait);
- if (signal_pending(current)) {
- /* wait was interrupted */
- up(&sd->sd_wbs);
- return -ERESTARTSYS;
- }
-
- spin_lock_irqsave(&sd->sd_wlock, flags);
- status = write_status_check(sd, count);
- }
- spin_unlock_irqrestore(&sd->sd_wlock, flags);
-
- /* release the write buffer and wake anyone who's waiting for it */
- up(&sd->sd_wbs);
-
- /* return the number of characters accepted (should be the complete
- * "chunk" as requested)
- */
- if ((status >= 0) && (status < count)) {
- pr_debug("Didn't accept the full chunk; %d of %d\n",
- status, (int) count);
- }
- return status;
-}
-
-static __poll_t
-scdrv_poll(struct file *file, struct poll_table_struct *wait)
-{
- __poll_t mask = 0;
- int status = 0;
- struct subch_data_s *sd = (struct subch_data_s *) file->private_data;
- unsigned long flags;
-
- poll_wait(file, &sd->sd_rq, wait);
- poll_wait(file, &sd->sd_wq, wait);
-
- spin_lock_irqsave(&sd->sd_rlock, flags);
- spin_lock(&sd->sd_wlock);
- status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
- spin_unlock(&sd->sd_wlock);
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
-
- if (status > 0) {
- if (status & SAL_IROUTER_INTR_RECV) {
- mask |= EPOLLIN | EPOLLRDNORM;
- }
- if (status & SAL_IROUTER_INTR_XMIT) {
- mask |= EPOLLOUT | EPOLLWRNORM;
- }
- }
-
- return mask;
-}
-
-static const struct file_operations scdrv_fops = {
- .owner = THIS_MODULE,
- .read = scdrv_read,
- .write = scdrv_write,
- .poll = scdrv_poll,
- .open = scdrv_open,
- .release = scdrv_release,
- .llseek = noop_llseek,
-};
-
-static struct class *snsc_class;
-
-/*
- * scdrv_init
- *
- * Called at boot time to initialize the system controller communication
- * facility.
- */
-int __init
-scdrv_init(void)
-{
- geoid_t geoid;
- cnodeid_t cnode;
- char devname[32];
- char *devnamep;
- struct sysctl_data_s *scd;
- void *salbuf;
- dev_t first_dev, dev;
- nasid_t event_nasid;
-
- if (!ia64_platform_is("sn2"))
- return -ENODEV;
-
- event_nasid = ia64_sn_get_console_nasid();
-
- snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
- if (IS_ERR(snsc_class)) {
- printk("%s: failed to allocate class\n", __func__);
- return PTR_ERR(snsc_class);
- }
-
- if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
- SYSCTL_BASENAME) < 0) {
- printk("%s: failed to register SN system controller device\n",
- __func__);
- return -ENODEV;
- }
-
- for (cnode = 0; cnode < num_cnodes; cnode++) {
- geoid = cnodeid_get_geoid(cnode);
- devnamep = devname;
- format_module_id(devnamep, geo_module(geoid),
- MODULE_FORMAT_BRIEF);
- devnamep = devname + strlen(devname);
- sprintf(devnamep, "^%d#%d", geo_slot(geoid),
- geo_slab(geoid));
-
- /* allocate sysctl device data */
- scd = kzalloc(sizeof (struct sysctl_data_s),
- GFP_KERNEL);
- if (!scd) {
- printk("%s: failed to allocate device info"
- "for %s/%s\n", __func__,
- SYSCTL_BASENAME, devname);
- continue;
- }
-
- /* initialize sysctl device data fields */
- scd->scd_nasid = cnodeid_to_nasid(cnode);
- if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) {
- printk("%s: failed to allocate driver buffer"
- "(%s%s)\n", __func__,
- SYSCTL_BASENAME, devname);
- kfree(scd);
- continue;
- }
-
- if (ia64_sn_irtr_init(scd->scd_nasid, salbuf,
- SCDRV_BUFSZ) < 0) {
- printk
- ("%s: failed to initialize SAL for"
- " system controller communication"
- " (%s/%s): outdated PROM?\n",
- __func__, SYSCTL_BASENAME, devname);
- kfree(scd);
- kfree(salbuf);
- continue;
- }
-
- dev = first_dev + cnode;
- cdev_init(&scd->scd_cdev, &scdrv_fops);
- if (cdev_add(&scd->scd_cdev, dev, 1)) {
- printk("%s: failed to register system"
- " controller device (%s%s)\n",
- __func__, SYSCTL_BASENAME, devname);
- kfree(scd);
- kfree(salbuf);
- continue;
- }
-
- device_create(snsc_class, NULL, dev, NULL,
- "%s", devname);
-
- ia64_sn_irtr_intr_enable(scd->scd_nasid,
- 0 /*ignored */ ,
- SAL_IROUTER_INTR_RECV);
-
- /* on the console nasid, prepare to receive
- * system controller environmental events
- */
- if(scd->scd_nasid == event_nasid) {
- scdrv_event_init(scd);
- }
- }
- return 0;
-}
-device_initcall(scdrv_init);
diff --git a/drivers/char/snsc.h b/drivers/char/snsc.h
deleted file mode 100644
index e8c52c882b21..000000000000
--- a/drivers/char/snsc.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * SN Platform system controller communication support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * This file contains macros and data types for communication with the
- * system controllers in SGI SN systems.
- */
-
-#ifndef _SN_SYSCTL_H_
-#define _SN_SYSCTL_H_
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/semaphore.h>
-#include <asm/sn/types.h>
-
-#define CHUNKSIZE 127
-
-/* This structure is used to track an open subchannel. */
-struct subch_data_s {
- nasid_t sd_nasid; /* node on which the subchannel was opened */
- int sd_subch; /* subchannel number */
- spinlock_t sd_rlock; /* monitor lock for rsv */
- spinlock_t sd_wlock; /* monitor lock for wsv */
- wait_queue_head_t sd_rq; /* wait queue for readers */
- wait_queue_head_t sd_wq; /* wait queue for writers */
- struct semaphore sd_rbs; /* semaphore for read buffer */
- struct semaphore sd_wbs; /* semaphore for write buffer */
-
- char sd_rb[CHUNKSIZE]; /* read buffer */
- char sd_wb[CHUNKSIZE]; /* write buffer */
-};
-
-struct sysctl_data_s {
- struct cdev scd_cdev; /* Character device info */
- nasid_t scd_nasid; /* Node on which subchannels are opened. */
-};
-
-
-/* argument types */
-#define IR_ARG_INT 0x00 /* 4-byte integer (big-endian) */
-#define IR_ARG_ASCII 0x01 /* null-terminated ASCII string */
-#define IR_ARG_UNKNOWN 0x80 /* unknown data type. The low
- * 7 bits will contain the data
- * length. */
-#define IR_ARG_UNKNOWN_LENGTH_MASK 0x7f
-
-
-/* system controller event codes */
-#define EV_CLASS_MASK 0xf000ul
-#define EV_SEVERITY_MASK 0x0f00ul
-#define EV_COMPONENT_MASK 0x00fful
-
-#define EV_CLASS_POWER 0x1000ul
-#define EV_CLASS_FAN 0x2000ul
-#define EV_CLASS_TEMP 0x3000ul
-#define EV_CLASS_ENV 0x4000ul
-#define EV_CLASS_TEST_FAULT 0x5000ul
-#define EV_CLASS_TEST_WARNING 0x6000ul
-#define EV_CLASS_PWRD_NOTIFY 0x8000ul
-
-/* ENV class codes */
-#define ENV_PWRDN_PEND 0x4101ul
-
-#define EV_SEVERITY_POWER_STABLE 0x0000ul
-#define EV_SEVERITY_POWER_LOW_WARNING 0x0100ul
-#define EV_SEVERITY_POWER_HIGH_WARNING 0x0200ul
-#define EV_SEVERITY_POWER_HIGH_FAULT 0x0300ul
-#define EV_SEVERITY_POWER_LOW_FAULT 0x0400ul
-
-#define EV_SEVERITY_FAN_STABLE 0x0000ul
-#define EV_SEVERITY_FAN_WARNING 0x0100ul
-#define EV_SEVERITY_FAN_FAULT 0x0200ul
-
-#define EV_SEVERITY_TEMP_STABLE 0x0000ul
-#define EV_SEVERITY_TEMP_ADVISORY 0x0100ul
-#define EV_SEVERITY_TEMP_CRITICAL 0x0200ul
-#define EV_SEVERITY_TEMP_FAULT 0x0300ul
-
-void scdrv_event_init(struct sysctl_data_s *);
-
-#endif /* _SN_SYSCTL_H_ */
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
deleted file mode 100644
index e452673dff66..000000000000
--- a/drivers/char/snsc_event.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * SN Platform system controller communication support
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004-2006 Silicon Graphics, Inc. All rights reserved.
- */
-
-/*
- * System controller event handler
- *
- * These routines deal with environmental events arriving from the
- * system controllers.
- */
-
-#include <linux/interrupt.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-#include <asm/byteorder.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/unaligned.h>
-#include "snsc.h"
-
-static struct subch_data_s *event_sd;
-
-void scdrv_event(unsigned long);
-DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0);
-
-/*
- * scdrv_event_interrupt
- *
- * Pull incoming environmental events off the physical link to the
- * system controller and put them in a temporary holding area in SAL.
- * Schedule scdrv_event() to move them along to their ultimate
- * destination.
- */
-static irqreturn_t
-scdrv_event_interrupt(int irq, void *subch_data)
-{
- struct subch_data_s *sd = subch_data;
- unsigned long flags;
- int status;
-
- spin_lock_irqsave(&sd->sd_rlock, flags);
- status = ia64_sn_irtr_intr(sd->sd_nasid, sd->sd_subch);
-
- if ((status > 0) && (status & SAL_IROUTER_INTR_RECV)) {
- tasklet_schedule(&sn_sysctl_event);
- }
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
- return IRQ_HANDLED;
-}
-
-
-/*
- * scdrv_parse_event
- *
- * Break an event (as read from SAL) into useful pieces so we can decide
- * what to do with it.
- */
-static int
-scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
-{
- char *desc_end;
-
- /* record event source address */
- *src = get_unaligned_be32(event);
- event += 4; /* move on to event code */
-
- /* record the system controller's event code */
- *code = get_unaligned_be32(event);
- event += 4; /* move on to event arguments */
-
- /* how many arguments are in the packet? */
- if (*event++ != 2) {
- /* if not 2, give up */
- return -1;
- }
-
- /* parse out the ESP code */
- if (*event++ != IR_ARG_INT) {
- /* not an integer argument, so give up */
- return -1;
- }
- *esp_code = get_unaligned_be32(event);
- event += 4;
-
- /* parse out the event description */
- if (*event++ != IR_ARG_ASCII) {
- /* not an ASCII string, so give up */
- return -1;
- }
- event[CHUNKSIZE-1] = '\0'; /* ensure this string ends! */
- event += 2; /* skip leading CR/LF */
- desc_end = desc + sprintf(desc, "%s", event);
-
- /* strip trailing CR/LF (if any) */
- for (desc_end--;
- (desc_end != desc) && ((*desc_end == 0xd) || (*desc_end == 0xa));
- desc_end--) {
- *desc_end = '\0';
- }
-
- return 0;
-}
-
-
-/*
- * scdrv_event_severity
- *
- * Figure out how urgent a message we should write to the console/syslog
- * via printk.
- */
-static char *
-scdrv_event_severity(int code)
-{
- int ev_class = (code & EV_CLASS_MASK);
- int ev_severity = (code & EV_SEVERITY_MASK);
- char *pk_severity = KERN_NOTICE;
-
- switch (ev_class) {
- case EV_CLASS_POWER:
- switch (ev_severity) {
- case EV_SEVERITY_POWER_LOW_WARNING:
- case EV_SEVERITY_POWER_HIGH_WARNING:
- pk_severity = KERN_WARNING;
- break;
- case EV_SEVERITY_POWER_HIGH_FAULT:
- case EV_SEVERITY_POWER_LOW_FAULT:
- pk_severity = KERN_ALERT;
- break;
- }
- break;
- case EV_CLASS_FAN:
- switch (ev_severity) {
- case EV_SEVERITY_FAN_WARNING:
- pk_severity = KERN_WARNING;
- break;
- case EV_SEVERITY_FAN_FAULT:
- pk_severity = KERN_CRIT;
- break;
- }
- break;
- case EV_CLASS_TEMP:
- switch (ev_severity) {
- case EV_SEVERITY_TEMP_ADVISORY:
- pk_severity = KERN_WARNING;
- break;
- case EV_SEVERITY_TEMP_CRITICAL:
- pk_severity = KERN_CRIT;
- break;
- case EV_SEVERITY_TEMP_FAULT:
- pk_severity = KERN_ALERT;
- break;
- }
- break;
- case EV_CLASS_ENV:
- pk_severity = KERN_ALERT;
- break;
- case EV_CLASS_TEST_FAULT:
- pk_severity = KERN_ALERT;
- break;
- case EV_CLASS_TEST_WARNING:
- pk_severity = KERN_WARNING;
- break;
- case EV_CLASS_PWRD_NOTIFY:
- pk_severity = KERN_ALERT;
- break;
- }
-
- return pk_severity;
-}
-
-
-/*
- * scdrv_dispatch_event
- *
- * Do the right thing with an incoming event. That's often nothing
- * more than printing it to the system log. For power-down notifications
- * we start a graceful shutdown.
- */
-static void
-scdrv_dispatch_event(char *event, int len)
-{
- static int snsc_shutting_down = 0;
- int code, esp_code, src, class;
- char desc[CHUNKSIZE];
- char *severity;
-
- if (scdrv_parse_event(event, &src, &code, &esp_code, desc) < 0) {
- /* ignore uninterpretible event */
- return;
- }
-
- /* how urgent is the message? */
- severity = scdrv_event_severity(code);
-
- class = (code & EV_CLASS_MASK);
-
- if (class == EV_CLASS_PWRD_NOTIFY || code == ENV_PWRDN_PEND) {
- if (snsc_shutting_down)
- return;
-
- snsc_shutting_down = 1;
-
- /* give a message for each type of event */
- if (class == EV_CLASS_PWRD_NOTIFY)
- printk(KERN_NOTICE "Power off indication received."
- " Sending SIGPWR to init...\n");
- else if (code == ENV_PWRDN_PEND)
- printk(KERN_CRIT "WARNING: Shutting down the system"
- " due to a critical environmental condition."
- " Sending SIGPWR to init...\n");
-
- /* give a SIGPWR signal to init proc */
- kill_cad_pid(SIGPWR, 0);
- } else {
- /* print to system log */
- printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
- }
-}
-
-
-/*
- * scdrv_event
- *
- * Called as a tasklet when an event arrives from the L1. Read the event
- * from where it's temporarily stored in SAL and call scdrv_dispatch_event()
- * to send it on its way. Keep trying to read events until SAL indicates
- * that there are no more immediately available.
- */
-void
-scdrv_event(unsigned long dummy)
-{
- int status;
- int len;
- unsigned long flags;
- struct subch_data_s *sd = event_sd;
-
- /* anything to read? */
- len = CHUNKSIZE;
- spin_lock_irqsave(&sd->sd_rlock, flags);
- status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
- sd->sd_rb, &len);
-
- while (!(status < 0)) {
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
- scdrv_dispatch_event(sd->sd_rb, len);
- len = CHUNKSIZE;
- spin_lock_irqsave(&sd->sd_rlock, flags);
- status = ia64_sn_irtr_recv(sd->sd_nasid, sd->sd_subch,
- sd->sd_rb, &len);
- }
- spin_unlock_irqrestore(&sd->sd_rlock, flags);
-}
-
-
-/*
- * scdrv_event_init
- *
- * Sets up a system controller subchannel to begin receiving event
- * messages. This is sort of a specialized version of scdrv_open()
- * in drivers/char/sn_sysctl.c.
- */
-void
-scdrv_event_init(struct sysctl_data_s *scd)
-{
- int rv;
-
- event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
- if (event_sd == NULL) {
- printk(KERN_WARNING "%s: couldn't allocate subchannel info"
- " for event monitoring\n", __func__);
- return;
- }
-
- /* initialize subch_data_s fields */
- event_sd->sd_nasid = scd->scd_nasid;
- spin_lock_init(&event_sd->sd_rlock);
-
- /* ask the system controllers to send events to this node */
- event_sd->sd_subch = ia64_sn_sysctl_event_init(scd->scd_nasid);
-
- if (event_sd->sd_subch < 0) {
- kfree(event_sd);
- printk(KERN_WARNING "%s: couldn't open event subchannel\n",
- __func__);
- return;
- }
-
- /* hook event subchannel up to the system controller interrupt */
- rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt,
- IRQF_SHARED, "system controller events", event_sd);
- if (rv) {
- printk(KERN_WARNING "%s: irq request failed (%d)\n",
- __func__, rv);
- ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
- kfree(event_sd);
- return;
- }
-}
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 9eada392df15..1c227ea8ecd3 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -567,15 +567,6 @@ config BLK_DEV_SVWKS
This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
chipsets.
-config BLK_DEV_SGIIOC4
- tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
- depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
- select BLK_DEV_IDEDMA_PCI
- help
- This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
- chipset, which has one channel and can support two devices.
- Please say Y here if you have an Altix System from SGI.
-
config BLK_DEV_SIIMAGE
tristate "Silicon Image chipset support"
select BLK_DEV_IDEDMA_PCI
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 9f617a77970f..cac02db4098d 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -59,7 +59,6 @@ obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o
obj-$(CONFIG_BLK_DEV_PIIX) += piix.o
obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o
obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o
-obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o
obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c
deleted file mode 100644
index 2d35e9f7516f..000000000000
--- a/drivers/ide/sgiioc4.c
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved.
- * Copyright (C) 2008-2009 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/scatterlist.h>
-#include <linux/ioc4.h>
-#include <linux/io.h>
-#include <linux/ide.h>
-
-#define DRV_NAME "SGIIOC4"
-
-/* IOC4 Specific Definitions */
-#define IOC4_CMD_OFFSET 0x100
-#define IOC4_CTRL_OFFSET 0x120
-#define IOC4_DMA_OFFSET 0x140
-#define IOC4_INTR_OFFSET 0x0
-
-#define IOC4_TIMING 0x00
-#define IOC4_DMA_PTR_L 0x01
-#define IOC4_DMA_PTR_H 0x02
-#define IOC4_DMA_ADDR_L 0x03
-#define IOC4_DMA_ADDR_H 0x04
-#define IOC4_BC_DEV 0x05
-#define IOC4_BC_MEM 0x06
-#define IOC4_DMA_CTRL 0x07
-#define IOC4_DMA_END_ADDR 0x08
-
-/* Bits in the IOC4 Control/Status Register */
-#define IOC4_S_DMA_START 0x01
-#define IOC4_S_DMA_STOP 0x02
-#define IOC4_S_DMA_DIR 0x04
-#define IOC4_S_DMA_ACTIVE 0x08
-#define IOC4_S_DMA_ERROR 0x10
-#define IOC4_ATA_MEMERR 0x02
-
-/* Read/Write Directions */
-#define IOC4_DMA_WRITE 0x04
-#define IOC4_DMA_READ 0x00
-
-/* Interrupt Register Offsets */
-#define IOC4_INTR_REG 0x03
-#define IOC4_INTR_SET 0x05
-#define IOC4_INTR_CLEAR 0x07
-
-#define IOC4_IDE_CACHELINE_SIZE 128
-#define IOC4_CMD_CTL_BLK_SIZE 0x20
-#define IOC4_SUPPORTED_FIRMWARE_REV 46
-
-struct ioc4_dma_regs {
- u32 timing_reg0;
- u32 timing_reg1;
- u32 low_mem_ptr;
- u32 high_mem_ptr;
- u32 low_mem_addr;
- u32 high_mem_addr;
- u32 dev_byte_count;
- u32 mem_byte_count;
- u32 status;
-};
-
-/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */
-/* IOC4 has only 1 IDE channel */
-#define IOC4_PRD_BYTES 16
-#define IOC4_PRD_ENTRIES (PAGE_SIZE / (4 * IOC4_PRD_BYTES))
-
-
-static void sgiioc4_init_hwif_ports(struct ide_hw *hw,
- unsigned long data_port,
- unsigned long ctrl_port,
- unsigned long irq_port)
-{
- unsigned long reg = data_port;
- int i;
-
- /* Registers are word (32 bit) aligned */
- for (i = 0; i <= 7; i++)
- hw->io_ports_array[i] = reg + i * 4;
-
- hw->io_ports.ctl_addr = ctrl_port;
- hw->io_ports.irq_addr = irq_port;
-}
-
-static int sgiioc4_checkirq(ide_hwif_t *hwif)
-{
- unsigned long intr_addr = hwif->io_ports.irq_addr + IOC4_INTR_REG * 4;
-
- if (readl((void __iomem *)intr_addr) & 0x03)
- return 1;
-
- return 0;
-}
-
-static u8 sgiioc4_read_status(ide_hwif_t *);
-
-static int sgiioc4_clearirq(ide_drive_t *drive)
-{
- u32 intr_reg;
- ide_hwif_t *hwif = drive->hwif;
- struct ide_io_ports *io_ports = &hwif->io_ports;
- unsigned long other_ir = io_ports->irq_addr + (IOC4_INTR_REG << 2);
-
- /* Code to check for PCI error conditions */
- intr_reg = readl((void __iomem *)other_ir);
- if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */
- /*
- * Using sgiioc4_read_status to read the Status register has a
- * side effect of clearing the interrupt. The first read should
- * clear it if it is set. The second read should return
- * a "clear" status if it got cleared. If not, then spin
- * for a bit trying to clear it.
- */
- u8 stat = sgiioc4_read_status(hwif);
- int count = 0;
-
- stat = sgiioc4_read_status(hwif);
- while ((stat & ATA_BUSY) && (count++ < 100)) {
- udelay(1);
- stat = sgiioc4_read_status(hwif);
- }
-
- if (intr_reg & 0x02) {
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- /* Error when transferring DMA data on PCI bus */
- u32 pci_err_addr_low, pci_err_addr_high,
- pci_stat_cmd_reg;
-
- pci_err_addr_low =
- readl((void __iomem *)io_ports->irq_addr);
- pci_err_addr_high =
- readl((void __iomem *)(io_ports->irq_addr + 4));
- pci_read_config_dword(dev, PCI_COMMAND,
- &pci_stat_cmd_reg);
- printk(KERN_ERR "%s(%s): PCI Bus Error when doing DMA: "
- "status-cmd reg is 0x%x\n",
- __func__, drive->name, pci_stat_cmd_reg);
- printk(KERN_ERR "%s(%s): PCI Error Address is 0x%x%x\n",
- __func__, drive->name,
- pci_err_addr_high, pci_err_addr_low);
- /* Clear the PCI Error indicator */
- pci_write_config_dword(dev, PCI_COMMAND, 0x00000146);
- }
-
- /* Clear the Interrupt, Error bits on the IOC4 */
- writel(0x03, (void __iomem *)other_ir);
-
- intr_reg = readl((void __iomem *)other_ir);
- }
-
- return intr_reg & 3;
-}
-
-static void sgiioc4_dma_start(ide_drive_t *drive)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4;
- unsigned int reg = readl((void __iomem *)ioc4_dma_addr);
- unsigned int temp_reg = reg | IOC4_S_DMA_START;
-
- writel(temp_reg, (void __iomem *)ioc4_dma_addr);
-}
-
-static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base)
-{
- unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
- u32 ioc4_dma;
- int count;
-
- count = 0;
- ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
- while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) {
- udelay(1);
- ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
- }
- return ioc4_dma;
-}
-
-/* Stops the IOC4 DMA Engine */
-static int sgiioc4_dma_end(ide_drive_t *drive)
-{
- u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
- ide_hwif_t *hwif = drive->hwif;
- unsigned long dma_base = hwif->dma_base;
- int dma_stat = 0;
- unsigned long *ending_dma = ide_get_hwifdata(hwif);
-
- writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4));
-
- ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
-
- if (ioc4_dma & IOC4_S_DMA_STOP) {
- printk(KERN_ERR
- "%s(%s): IOC4 DMA STOP bit is still 1 :"
- "ioc4_dma_reg 0x%x\n",
- __func__, drive->name, ioc4_dma);
- dma_stat = 1;
- }
-
- /*
- * The IOC4 will DMA 1's to the ending DMA area to indicate that
- * previous data DMA is complete. This is necessary because of relaxed
- * ordering between register reads and DMA writes on the Altix.
- */
- while ((cnt++ < 200) && (!valid)) {
- for (num = 0; num < 16; num++) {
- if (ending_dma[num]) {
- valid = 1;
- break;
- }
- }
- udelay(1);
- }
- if (!valid) {
- printk(KERN_ERR "%s(%s) : DMA incomplete\n", __func__,
- drive->name);
- dma_stat = 1;
- }
-
- bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4));
- bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4));
-
- if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) {
- if (bc_dev > bc_mem + 8) {
- printk(KERN_ERR
- "%s(%s): WARNING!! byte_count_dev %d "
- "!= byte_count_mem %d\n",
- __func__, drive->name, bc_dev, bc_mem);
- }
- }
-
- return dma_stat;
-}
-
-static void sgiioc4_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-}
-
-/* Returns 1 if DMA IRQ issued, 0 otherwise */
-static int sgiioc4_dma_test_irq(ide_drive_t *drive)
-{
- return sgiioc4_checkirq(drive->hwif);
-}
-
-static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
-{
- if (!on)
- sgiioc4_clearirq(drive);
-}
-
-static void sgiioc4_resetproc(ide_drive_t *drive)
-{
- struct ide_cmd *cmd = &drive->hwif->cmd;
-
- sgiioc4_dma_end(drive);
- ide_dma_unmap_sg(drive, cmd);
- sgiioc4_clearirq(drive);
-}
-
-static void sgiioc4_dma_lost_irq(ide_drive_t *drive)
-{
- sgiioc4_resetproc(drive);
-
- ide_dma_lost_irq(drive);
-}
-
-static u8 sgiioc4_read_status(ide_hwif_t *hwif)
-{
- unsigned long port = hwif->io_ports.status_addr;
- u8 reg = (u8) readb((void __iomem *) port);
-
- if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */
- unsigned long other_ir = port - 0x110;
- unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
-
- /* Clear the Interrupt, Error bits on the IOC4 */
- if (intr_reg & 0x03) {
- writel(0x03, (void __iomem *) other_ir);
- intr_reg = (u32) readl((void __iomem *) other_ir);
- }
- }
-
- return reg;
-}
-
-/* Creates a DMA map for the scatter-gather list entries */
-static int ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
- struct pci_dev *dev = to_pci_dev(hwif->dev);
- unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
- int num_ports = sizeof(struct ioc4_dma_regs);
- void *pad;
-
- printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
-
- if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) {
- printk(KERN_ERR "%s(%s) -- ERROR: addresses 0x%08lx to 0x%08lx "
- "already in use\n", __func__, hwif->name,
- dma_base, dma_base + num_ports - 1);
- return -1;
- }
-
- hwif->dma_base = (unsigned long)hwif->io_ports.irq_addr +
- IOC4_DMA_OFFSET;
-
- hwif->sg_max_nents = IOC4_PRD_ENTRIES;
-
- hwif->prd_max_nents = IOC4_PRD_ENTRIES;
- hwif->prd_ent_size = IOC4_PRD_BYTES;
-
- if (ide_allocate_dma_engine(hwif))
- goto dma_pci_alloc_failure;
-
- pad = dma_alloc_coherent(&dev->dev, IOC4_IDE_CACHELINE_SIZE,
- (dma_addr_t *)&hwif->extra_base, GFP_KERNEL);
- if (pad) {
- ide_set_hwifdata(hwif, pad);
- return 0;
- }
-
- ide_release_dma_engine(hwif);
-
- printk(KERN_ERR "%s(%s) -- ERROR: Unable to allocate DMA maps\n",
- __func__, hwif->name);
- printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name);
-
-dma_pci_alloc_failure:
- release_mem_region(dma_base, num_ports);
-
- return -1;
-}
-
-/* Initializes the IOC4 DMA Engine */
-static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t *drive)
-{
- u32 ioc4_dma;
- ide_hwif_t *hwif = drive->hwif;
- unsigned long dma_base = hwif->dma_base;
- unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
- u32 dma_addr, ending_dma_addr;
-
- ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
-
- if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
- printk(KERN_WARNING "%s(%s): Warning!! DMA from previous "
- "transfer was still active\n", __func__, drive->name);
- writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
- ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
-
- if (ioc4_dma & IOC4_S_DMA_STOP)
- printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is "
- "still 1\n", __func__, drive->name);
- }
-
- ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
- if (ioc4_dma & IOC4_S_DMA_ERROR) {
- printk(KERN_WARNING "%s(%s): Warning!! DMA Error during "
- "previous transfer, status 0x%x\n",
- __func__, drive->name, ioc4_dma);
- writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
- ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
-
- if (ioc4_dma & IOC4_S_DMA_STOP)
- printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is "
- "still 1\n", __func__, drive->name);
- }
-
- /* Address of the Scatter Gather List */
- dma_addr = cpu_to_le32(hwif->dmatable_dma);
- writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4));
-
- /* Address of the Ending DMA */
- memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE);
- ending_dma_addr = cpu_to_le32(hwif->extra_base);
- writel(ending_dma_addr, (void __iomem *)(dma_base +
- IOC4_DMA_END_ADDR * 4));
-
- writel(dma_direction, (void __iomem *)ioc4_dma_addr);
-}
-
-/* IOC4 Scatter Gather list Format */
-/* 128 Bit entries to support 64 bit addresses in the future */
-/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format */
-/* --------------------------------------------------------------------- */
-/* | Upper 32 bits - Zero | Lower 32 bits- address | */
-/* --------------------------------------------------------------------- */
-/* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| */
-/* --------------------------------------------------------------------- */
-/* Creates the scatter gather list, DMA Table */
-
-static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- ide_hwif_t *hwif = drive->hwif;
- unsigned int *table = hwif->dmatable_cpu;
- unsigned int count = 0, i = cmd->sg_nents;
- struct scatterlist *sg = hwif->sg_table;
-
- while (i && sg_dma_len(sg)) {
- dma_addr_t cur_addr;
- int cur_len;
- cur_addr = sg_dma_address(sg);
- cur_len = sg_dma_len(sg);
-
- while (cur_len) {
- if (count++ >= IOC4_PRD_ENTRIES) {
- printk(KERN_WARNING
- "%s: DMA table too small\n",
- drive->name);
- return 0;
- } else {
- u32 bcount =
- 0x10000 - (cur_addr & 0xffff);
-
- if (bcount > cur_len)
- bcount = cur_len;
-
- /*
- * Put the address, length in
- * the IOC4 dma-table format
- */
- *table = 0x0;
- table++;
- *table = cpu_to_be32(cur_addr);
- table++;
- *table = 0x0;
- table++;
-
- *table = cpu_to_be32(bcount);
- table++;
-
- cur_addr += bcount;
- cur_len -= bcount;
- }
- }
-
- sg = sg_next(sg);
- i--;
- }
-
- if (count) {
- table--;
- *table |= cpu_to_be32(0x80000000);
- return count;
- }
-
- return 0; /* revert to PIO for this request */
-}
-
-static int sgiioc4_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
- int ddir;
- u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-
- if (sgiioc4_build_dmatable(drive, cmd) == 0)
- /* try PIO instead of DMA */
- return 1;
-
- if (write)
- /* Writes TO the IOC4 FROM Main Memory */
- ddir = IOC4_DMA_READ;
- else
- /* Writes FROM the IOC4 TO Main Memory */
- ddir = IOC4_DMA_WRITE;
-
- sgiioc4_configure_for_dma(ddir, drive);
-
- return 0;
-}
-
-static const struct ide_tp_ops sgiioc4_tp_ops = {
- .exec_command = ide_exec_command,
- .read_status = sgiioc4_read_status,
- .read_altstatus = ide_read_altstatus,
- .write_devctl = ide_write_devctl,
-
- .dev_select = ide_dev_select,
- .tf_load = ide_tf_load,
- .tf_read = ide_tf_read,
-
- .input_data = ide_input_data,
- .output_data = ide_output_data,
-};
-
-static const struct ide_port_ops sgiioc4_port_ops = {
- .set_dma_mode = sgiioc4_set_dma_mode,
- /* reset DMA engine, clear IRQs */
- .resetproc = sgiioc4_resetproc,
-};
-
-static const struct ide_dma_ops sgiioc4_dma_ops = {
- .dma_host_set = sgiioc4_dma_host_set,
- .dma_setup = sgiioc4_dma_setup,
- .dma_start = sgiioc4_dma_start,
- .dma_end = sgiioc4_dma_end,
- .dma_test_irq = sgiioc4_dma_test_irq,
- .dma_lost_irq = sgiioc4_dma_lost_irq,
-};
-
-static const struct ide_port_info sgiioc4_port_info = {
- .name = DRV_NAME,
- .chipset = ide_pci,
- .init_dma = ide_dma_sgiioc4,
- .tp_ops = &sgiioc4_tp_ops,
- .port_ops = &sgiioc4_port_ops,
- .dma_ops = &sgiioc4_dma_ops,
- .host_flags = IDE_HFLAG_MMIO,
- .irq_flags = IRQF_SHARED,
- .mwdma_mask = ATA_MWDMA2_ONLY,
-};
-
-static int sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
-{
- unsigned long cmd_base, irqport;
- unsigned long bar0, cmd_phys_base, ctl;
- void __iomem *virt_base;
- struct ide_hw hw, *hws[] = { &hw };
- int rc;
-
- /* Get the CmdBlk and CtrlBlk base registers */
- bar0 = pci_resource_start(dev, 0);
- virt_base = pci_ioremap_bar(dev, 0);
- if (virt_base == NULL) {
- printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n",
- DRV_NAME, bar0);
- return -ENOMEM;
- }
- cmd_base = (unsigned long)virt_base + IOC4_CMD_OFFSET;
- ctl = (unsigned long)virt_base + IOC4_CTRL_OFFSET;
- irqport = (unsigned long)virt_base + IOC4_INTR_OFFSET;
-
- cmd_phys_base = bar0 + IOC4_CMD_OFFSET;
- if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
- DRV_NAME) == NULL) {
- printk(KERN_ERR "%s %s -- ERROR: addresses 0x%08lx to 0x%08lx "
- "already in use\n", DRV_NAME, pci_name(dev),
- cmd_phys_base, cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
- rc = -EBUSY;
- goto req_mem_rgn_err;
- }
-
- /* Initialize the IO registers */
- memset(&hw, 0, sizeof(hw));
- sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
- hw.irq = dev->irq;
- hw.dev = &dev->dev;
-
- /* Initialize chipset IRQ registers */
- writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
-
- rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL);
- if (!rc)
- return 0;
-
- release_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE);
-req_mem_rgn_err:
- iounmap(virt_base);
- return rc;
-}
-
-static unsigned int pci_init_sgiioc4(struct pci_dev *dev)
-{
- int ret;
-
- printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
- DRV_NAME, pci_name(dev), dev->revision);
-
- if (dev->revision < IOC4_SUPPORTED_FIRMWARE_REV) {
- printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
- "firmware is obsolete - please upgrade to "
- "revision46 or higher\n",
- DRV_NAME, pci_name(dev));
- ret = -EAGAIN;
- goto out;
- }
- ret = sgiioc4_ide_setup_pci_device(dev);
-out:
- return ret;
-}
-
-static int ioc4_ide_attach_one(struct ioc4_driver_data *idd)
-{
- /*
- * PCI-RT does not bring out IDE connection.
- * Do not attach to this particular IOC4.
- */
- if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
- return 0;
-
- return pci_init_sgiioc4(idd->idd_pdev);
-}
-
-static struct ioc4_submodule ioc4_ide_submodule = {
- .is_name = "IOC4_ide",
- .is_owner = THIS_MODULE,
- .is_probe = ioc4_ide_attach_one,
-};
-
-static int __init ioc4_ide_init(void)
-{
- return ioc4_register_submodule(&ioc4_ide_submodule);
-}
-
-late_initcall(ioc4_ide_init); /* Call only after IDE init is done */
-
-MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
-MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index a4ddeade8ac4..e3842eabcfdd 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -177,7 +177,7 @@ config DMAR_TABLE
config INTEL_IOMMU
bool "Support for Intel IOMMU using DMA Remapping Devices"
- depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC)
+ depends on PCI_MSI && ACPI && (X86 || IA64)
select IOMMU_API
select IOMMU_IOVA
select NEED_DMA_MAP_STATE
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 16900357afc2..45b61b8d8442 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -126,18 +126,6 @@ config INTEL_MID_PTI
an Intel Atom (non-netbook) mobile device containing a MIPI
P1149.7 standard implementation.
-config SGI_IOC4
- tristate "SGI IOC4 Base IO support"
- depends on PCI
- ---help---
- This option enables basic support for the IOC4 chip on certain
- SGI IO controller cards (IO9, IO10, and PCI-RT). This option
- does not enable any specific functions on such a card, but provides
- necessary infrastructure for other drivers to utilize.
-
- If you have an SGI Altix with an IOC4-based card say Y.
- Otherwise say N.
-
config TIFM_CORE
tristate "TI Flash Media interface support"
depends on PCI
@@ -200,9 +188,8 @@ config ENCLOSURE_SERVICES
config SGI_XP
tristate "Support communication between SGI SSIs"
depends on NET
- depends on (IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || X86_UV) && SMP
- select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
- select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2
+ depends on (IA64_SGI_UV || X86_UV) && SMP
+ depends on X86_64 || BROKEN
select SGI_GRU if X86_64 && SMP
---help---
An SGI machine can be divided into multiple Single System
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index abd8ae249746..8dae0a976200 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o
obj-$(CONFIG_QCOM_FASTRPC) += fastrpc.o
obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o
obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
-obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
deleted file mode 100644
index 9d0445a567db..000000000000
--- a/drivers/misc/ioc4.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2005-2006 Silicon Graphics, Inc. All Rights Reserved.
- */
-
-/* This file contains the master driver module for use by SGI IOC4 subdrivers.
- *
- * It allocates any resources shared between multiple subdevices, and
- * provides accessor functions (where needed) and the like for those
- * resources. It also provides a mechanism for the subdevice modules
- * to support loading and unloading.
- *
- * Non-shared resources (e.g. external interrupt A_INT_OUT register page
- * alias, serial port and UART registers) are handled by the subdevice
- * modules themselves.
- *
- * This is all necessary because IOC4 is not implemented as a multi-function
- * PCI device, but an amalgamation of disparate registers for several
- * types of device (ATA, serial, external interrupts). The normal
- * resource management in the kernel doesn't have quite the right interfaces
- * to handle this situation (e.g. multiple modules can't claim the same
- * PCI ID), thus this IOC4 master module.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ioc4.h>
-#include <linux/ktime.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/time.h>
-#include <asm/io.h>
-
-/***************
- * Definitions *
- ***************/
-
-/* Tweakable values */
-
-/* PCI bus speed detection/calibration */
-#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
-#define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */
-#define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */
-#define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */
-#define IOC4_CALIBRATE_HIGH_MHZ 75 /* Upper bound on bus speed sanity */
-#define IOC4_CALIBRATE_DEFAULT_MHZ 66 /* Assumed if sanity check fails */
-
-/************************
- * Submodule management *
- ************************/
-
-static DEFINE_MUTEX(ioc4_mutex);
-
-static LIST_HEAD(ioc4_devices);
-static LIST_HEAD(ioc4_submodules);
-
-/* Register an IOC4 submodule */
-int
-ioc4_register_submodule(struct ioc4_submodule *is)
-{
- struct ioc4_driver_data *idd;
-
- mutex_lock(&ioc4_mutex);
- list_add(&is->is_list, &ioc4_submodules);
-
- /* Initialize submodule for each IOC4 */
- if (!is->is_probe)
- goto out;
-
- list_for_each_entry(idd, &ioc4_devices, idd_list) {
- if (is->is_probe(idd)) {
- printk(KERN_WARNING
- "%s: IOC4 submodule %s probe failed "
- "for pci_dev %s",
- __func__, module_name(is->is_owner),
- pci_name(idd->idd_pdev));
- }
- }
- out:
- mutex_unlock(&ioc4_mutex);
- return 0;
-}
-
-/* Unregister an IOC4 submodule */
-void
-ioc4_unregister_submodule(struct ioc4_submodule *is)
-{
- struct ioc4_driver_data *idd;
-
- mutex_lock(&ioc4_mutex);
- list_del(&is->is_list);
-
- /* Remove submodule for each IOC4 */
- if (!is->is_remove)
- goto out;
-
- list_for_each_entry(idd, &ioc4_devices, idd_list) {
- if (is->is_remove(idd)) {
- printk(KERN_WARNING
- "%s: IOC4 submodule %s remove failed "
- "for pci_dev %s.\n",
- __func__, module_name(is->is_owner),
- pci_name(idd->idd_pdev));
- }
- }
- out:
- mutex_unlock(&ioc4_mutex);
-}
-
-/*********************
- * Device management *
- *********************/
-
-#define IOC4_CALIBRATE_LOW_LIMIT \
- (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ)
-#define IOC4_CALIBRATE_HIGH_LIMIT \
- (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ)
-#define IOC4_CALIBRATE_DEFAULT \
- (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ)
-
-#define IOC4_CALIBRATE_END \
- (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD)
-
-#define IOC4_INT_OUT_MODE_TOGGLE 0x7 /* Toggle INT_OUT every COUNT+1 ticks */
-
-/* Determines external interrupt output clock period of the PCI bus an
- * IOC4 is attached to. This value can be used to determine the PCI
- * bus speed.
- *
- * IOC4 has a design feature that various internal timers are derived from
- * the PCI bus clock. This causes IOC4 device drivers to need to take the
- * bus speed into account when setting various register values (e.g. INT_OUT
- * register COUNT field, UART divisors, etc). Since this information is
- * needed by several subdrivers, it is determined by the main IOC4 driver,
- * even though the following code utilizes external interrupt registers
- * to perform the speed calculation.
- */
-static void
-ioc4_clock_calibrate(struct ioc4_driver_data *idd)
-{
- union ioc4_int_out int_out;
- union ioc4_gpcr gpcr;
- unsigned int state, last_state;
- uint64_t start, end, period;
- unsigned int count;
-
- /* Enable output */
- gpcr.raw = 0;
- gpcr.fields.dir = IOC4_GPCR_DIR_0;
- gpcr.fields.int_out_en = 1;
- writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw);
-
- /* Reset to power-on state */
- writel(0, &idd->idd_misc_regs->int_out.raw);
-
- /* Set up square wave */
- int_out.raw = 0;
- int_out.fields.count = IOC4_CALIBRATE_COUNT;
- int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE;
- int_out.fields.diag = 0;
- writel(int_out.raw, &idd->idd_misc_regs->int_out.raw);
-
- /* Check square wave period averaged over some number of cycles */
- start = ktime_get_ns();
- state = 1; /* make sure the first read isn't a rising edge */
- for (count = 0; count <= IOC4_CALIBRATE_END; count++) {
- do { /* wait for a rising edge */
- last_state = state;
- int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
- state = int_out.fields.int_out;
- } while (last_state || !state);
-
- /* discard the first few cycles */
- if (count == IOC4_CALIBRATE_DISCARD)
- start = ktime_get_ns();
- }
- end = ktime_get_ns();
-
- /* Calculation rearranged to preserve intermediate precision.
- * Logically:
- * 1. "end - start" gives us the measurement period over all
- * the square wave cycles.
- * 2. Divide by number of square wave cycles to get the period
- * of a square wave cycle.
- * 3. Divide by 2*(int_out.fields.count+1), which is the formula
- * by which the IOC4 generates the square wave, to get the
- * period of an IOC4 INT_OUT count.
- */
- period = (end - start) /
- (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1));
-
- /* Bounds check the result. */
- if (period > IOC4_CALIBRATE_LOW_LIMIT ||
- period < IOC4_CALIBRATE_HIGH_LIMIT) {
- printk(KERN_INFO
- "IOC4 %s: Clock calibration failed. Assuming"
- "PCI clock is %d ns.\n",
- pci_name(idd->idd_pdev),
- IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
- period = IOC4_CALIBRATE_DEFAULT;
- } else {
- u64 ns = period;
-
- do_div(ns, IOC4_EXTINT_COUNT_DIVISOR);
- printk(KERN_DEBUG
- "IOC4 %s: PCI clock is %llu ns.\n",
- pci_name(idd->idd_pdev), (unsigned long long)ns);
- }
-
- /* Remember results. We store the extint clock period rather
- * than the PCI clock period so that greater precision is
- * retained. Divide by IOC4_EXTINT_COUNT_DIVISOR to get
- * PCI clock period.
- */
- idd->count_period = period;
-}
-
-/* There are three variants of IOC4 cards: IO9, IO10, and PCI-RT.
- * Each brings out different combinations of IOC4 signals, thus.
- * the IOC4 subdrivers need to know to which we're attached.
- *
- * We look for the presence of a SCSI (IO9) or SATA (IO10) controller
- * on the same PCI bus at slot number 3 to differentiate IO9 from IO10.
- * If neither is present, it's a PCI-RT.
- */
-static unsigned int
-ioc4_variant(struct ioc4_driver_data *idd)
-{
- struct pci_dev *pdev = NULL;
- int found = 0;
-
- /* IO9: Look for a QLogic ISP 12160 at the same bus and slot 3. */
- do {
- pdev = pci_get_device(PCI_VENDOR_ID_QLOGIC,
- PCI_DEVICE_ID_QLOGIC_ISP12160, pdev);
- if (pdev &&
- idd->idd_pdev->bus->number == pdev->bus->number &&
- 3 == PCI_SLOT(pdev->devfn))
- found = 1;
- } while (pdev && !found);
- if (NULL != pdev) {
- pci_dev_put(pdev);
- return IOC4_VARIANT_IO9;
- }
-
- /* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */
- pdev = NULL;
- do {
- pdev = pci_get_device(PCI_VENDOR_ID_VITESSE,
- PCI_DEVICE_ID_VITESSE_VSC7174, pdev);
- if (pdev &&
- idd->idd_pdev->bus->number == pdev->bus->number &&
- 3 == PCI_SLOT(pdev->devfn))
- found = 1;
- } while (pdev && !found);
- if (NULL != pdev) {
- pci_dev_put(pdev);
- return IOC4_VARIANT_IO10;
- }
-
- /* PCI-RT: No SCSI/SATA controller will be present */
- return IOC4_VARIANT_PCI_RT;
-}
-
-static void
-ioc4_load_modules(struct work_struct *work)
-{
- request_module("sgiioc4");
-}
-
-static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules);
-
-/* Adds a new instance of an IOC4 card */
-static int
-ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
- struct ioc4_driver_data *idd;
- struct ioc4_submodule *is;
- uint32_t pcmd;
- int ret;
-
- /* Enable IOC4 and take ownership of it */
- if ((ret = pci_enable_device(pdev))) {
- printk(KERN_WARNING
- "%s: Failed to enable IOC4 device for pci_dev %s.\n",
- __func__, pci_name(pdev));
- goto out;
- }
- pci_set_master(pdev);
-
- /* Set up per-IOC4 data */
- idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL);
- if (!idd) {
- printk(KERN_WARNING
- "%s: Failed to allocate IOC4 data for pci_dev %s.\n",
- __func__, pci_name(pdev));
- ret = -ENODEV;
- goto out_idd;
- }
- idd->idd_pdev = pdev;
- idd->idd_pci_id = pci_id;
-
- /* Map IOC4 misc registers. These are shared between subdevices
- * so the main IOC4 module manages them.
- */
- idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0);
- if (!idd->idd_bar0) {
- printk(KERN_WARNING
- "%s: Unable to find IOC4 misc resource "
- "for pci_dev %s.\n",
- __func__, pci_name(idd->idd_pdev));
- ret = -ENODEV;
- goto out_pci;
- }
- if (!request_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
- "ioc4_misc")) {
- printk(KERN_WARNING
- "%s: Unable to request IOC4 misc region "
- "for pci_dev %s.\n",
- __func__, pci_name(idd->idd_pdev));
- ret = -ENODEV;
- goto out_pci;
- }
- idd->idd_misc_regs = ioremap(idd->idd_bar0,
- sizeof(struct ioc4_misc_regs));
- if (!idd->idd_misc_regs) {
- printk(KERN_WARNING
- "%s: Unable to remap IOC4 misc region "
- "for pci_dev %s.\n",
- __func__, pci_name(idd->idd_pdev));
- ret = -ENODEV;
- goto out_misc_region;
- }
-
- /* Failsafe portion of per-IOC4 initialization */
-
- /* Detect card variant */
- idd->idd_variant = ioc4_variant(idd);
- printk(KERN_INFO "IOC4 %s: %s card detected.\n", pci_name(pdev),
- idd->idd_variant == IOC4_VARIANT_IO9 ? "IO9" :
- idd->idd_variant == IOC4_VARIANT_PCI_RT ? "PCI-RT" :
- idd->idd_variant == IOC4_VARIANT_IO10 ? "IO10" : "unknown");
-
- /* Initialize IOC4 */
- pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
- pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
- pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
-
- /* Determine PCI clock */
- ioc4_clock_calibrate(idd);
-
- /* Disable/clear all interrupts. Need to do this here lest
- * one submodule request the shared IOC4 IRQ, but interrupt
- * is generated by a different subdevice.
- */
- /* Disable */
- writel(~0, &idd->idd_misc_regs->other_iec.raw);
- writel(~0, &idd->idd_misc_regs->sio_iec);
- /* Clear (i.e. acknowledge) */
- writel(~0, &idd->idd_misc_regs->other_ir.raw);
- writel(~0, &idd->idd_misc_regs->sio_ir);
-
- /* Track PCI-device specific data */
- idd->idd_serial_data = NULL;
- pci_set_drvdata(idd->idd_pdev, idd);
-
- mutex_lock(&ioc4_mutex);
- list_add_tail(&idd->idd_list, &ioc4_devices);
-
- /* Add this IOC4 to all submodules */
- list_for_each_entry(is, &ioc4_submodules, is_list) {
- if (is->is_probe && is->is_probe(idd)) {
- printk(KERN_WARNING
- "%s: IOC4 submodule 0x%s probe failed "
- "for pci_dev %s.\n",
- __func__, module_name(is->is_owner),
- pci_name(idd->idd_pdev));
- }
- }
- mutex_unlock(&ioc4_mutex);
-
- /* Request sgiioc4 IDE driver on boards that bring that functionality
- * off of IOC4. The root filesystem may be hosted on a drive connected
- * to IOC4, so we need to make sure the sgiioc4 driver is loaded as it
- * won't be picked up by modprobes due to the ioc4 module owning the
- * PCI device.
- */
- if (idd->idd_variant != IOC4_VARIANT_PCI_RT) {
- /* Request the module from a work procedure as the modprobe
- * goes out to a userland helper and that will hang if done
- * directly from ioc4_probe().
- */
- printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n");
- schedule_work(&ioc4_load_modules_work);
- }
-
- return 0;
-
-out_misc_region:
- release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
-out_pci:
- kfree(idd);
-out_idd:
- pci_disable_device(pdev);
-out:
- return ret;
-}
-
-/* Removes a particular instance of an IOC4 card. */
-static void
-ioc4_remove(struct pci_dev *pdev)
-{
- struct ioc4_submodule *is;
- struct ioc4_driver_data *idd;
-
- idd = pci_get_drvdata(pdev);
-
- /* Remove this IOC4 from all submodules */
- mutex_lock(&ioc4_mutex);
- list_for_each_entry(is, &ioc4_submodules, is_list) {
- if (is->is_remove && is->is_remove(idd)) {
- printk(KERN_WARNING
- "%s: IOC4 submodule 0x%s remove failed "
- "for pci_dev %s.\n",
- __func__, module_name(is->is_owner),
- pci_name(idd->idd_pdev));
- }
- }
- mutex_unlock(&ioc4_mutex);
-
- /* Release resources */
- iounmap(idd->idd_misc_regs);
- if (!idd->idd_bar0) {
- printk(KERN_WARNING
- "%s: Unable to get IOC4 misc mapping for pci_dev %s. "
- "Device removal may be incomplete.\n",
- __func__, pci_name(idd->idd_pdev));
- }
- release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
-
- /* Disable IOC4 and relinquish */
- pci_disable_device(pdev);
-
- /* Remove and free driver data */
- mutex_lock(&ioc4_mutex);
- list_del(&idd->idd_list);
- mutex_unlock(&ioc4_mutex);
- kfree(idd);
-}
-
-static const struct pci_device_id ioc4_id_table[] = {
- {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
- PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
- {0}
-};
-
-static struct pci_driver ioc4_driver = {
- .name = "IOC4",
- .id_table = ioc4_id_table,
- .probe = ioc4_probe,
- .remove = ioc4_remove,
-};
-
-MODULE_DEVICE_TABLE(pci, ioc4_id_table);
-
-/*********************
- * Module management *
- *********************/
-
-/* Module load */
-static int __init
-ioc4_init(void)
-{
- return pci_register_driver(&ioc4_driver);
-}
-
-/* Module unload */
-static void __exit
-ioc4_exit(void)
-{
- /* Ensure ioc4_load_modules() has completed before exiting */
- flush_work(&ioc4_load_modules_work);
- pci_unregister_driver(&ioc4_driver);
-}
-
-module_init(ioc4_init);
-module_exit(ioc4_exit);
-
-MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan@sgi.com>");
-MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(ioc4_register_submodule);
-EXPORT_SYMBOL(ioc4_unregister_submodule);
diff --git a/drivers/misc/sgi-xp/Makefile b/drivers/misc/sgi-xp/Makefile
index bbb622c19c06..34c55a4045af 100644
--- a/drivers/misc/sgi-xp/Makefile
+++ b/drivers/misc/sgi-xp/Makefile
@@ -4,17 +4,10 @@
#
obj-$(CONFIG_SGI_XP) += xp.o
-xp-y := xp_main.o
-xp-$(CONFIG_IA64_SGI_SN2) += xp_sn2.o xp_nofault.o
-xp-$(CONFIG_IA64_GENERIC) += xp_sn2.o xp_nofault.o
-xp-$(CONFIG_IA64_SGI_UV) += xp_uv.o
-xp-$(CONFIG_X86_64) += xp_uv.o
+xp-y := xp_main.o xp_uv.o
obj-$(CONFIG_SGI_XP) += xpc.o
-xpc-y := xpc_main.o xpc_channel.o xpc_partition.o
-xpc-$(CONFIG_IA64_SGI_SN2) += xpc_sn2.o
-xpc-$(CONFIG_IA64_GENERIC) += xpc_sn2.o
-xpc-$(CONFIG_IA64_SGI_UV) += xpc_uv.o
-xpc-$(CONFIG_X86_64) += xpc_uv.o
+xpc-y := xpc_main.o xpc_channel.o xpc_partition.o \
+ xpc_uv.o
obj-$(CONFIG_SGI_XP) += xpnet.o
diff --git a/drivers/misc/sgi-xp/xp.h b/drivers/misc/sgi-xp/xp.h
index b8069eec18cb..06469b12aced 100644
--- a/drivers/misc/sgi-xp/xp.h
+++ b/drivers/misc/sgi-xp/xp.h
@@ -24,23 +24,6 @@
#define is_uv() 0
#endif
-#if defined CONFIG_IA64
-#include <asm/sn/arch.h> /* defines is_shub1() and is_shub2() */
-#define is_shub() ia64_platform_is("sn2")
-#endif
-
-#ifndef is_shub1
-#define is_shub1() 0
-#endif
-
-#ifndef is_shub2
-#define is_shub2() 0
-#endif
-
-#ifndef is_shub
-#define is_shub() 0
-#endif
-
#ifdef USE_DBUG_ON
#define DBUG_ON(condition) BUG_ON(condition)
#else
@@ -360,9 +343,7 @@ extern int xp_nofault_PIOR(void *);
extern int xp_error_PIOR(void);
extern struct device *xp;
-extern enum xp_retval xp_init_sn2(void);
extern enum xp_retval xp_init_uv(void);
-extern void xp_exit_sn2(void);
extern void xp_exit_uv(void);
#endif /* _DRIVERS_MISC_SGIXP_XP_H */
diff --git a/drivers/misc/sgi-xp/xp_main.c b/drivers/misc/sgi-xp/xp_main.c
index 6d7f557fd1c1..5fd94d836070 100644
--- a/drivers/misc/sgi-xp/xp_main.c
+++ b/drivers/misc/sgi-xp/xp_main.c
@@ -233,9 +233,7 @@ xp_init(void)
for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++)
mutex_init(&xpc_registrations[ch_number].mutex);
- if (is_shub())
- ret = xp_init_sn2();
- else if (is_uv())
+ if (is_uv())
ret = xp_init_uv();
else
ret = 0;
@@ -251,9 +249,7 @@ module_init(xp_init);
void __exit
xp_exit(void)
{
- if (is_shub())
- xp_exit_sn2();
- else if (is_uv())
+ if (is_uv())
xp_exit_uv();
}
diff --git a/drivers/misc/sgi-xp/xp_nofault.S b/drivers/misc/sgi-xp/xp_nofault.S
deleted file mode 100644
index e38d43319429..000000000000
--- a/drivers/misc/sgi-xp/xp_nofault.S
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2004-2008 Silicon Graphics, Inc. All Rights Reserved.
- */
-
-/*
- * The xp_nofault_PIOR function takes a pointer to a remote PIO register
- * and attempts to load and consume a value from it. This function
- * will be registered as a nofault code block. In the event that the
- * PIO read fails, the MCA handler will force the error to look
- * corrected and vector to the xp_error_PIOR which will return an error.
- *
- * The definition of "consumption" and the time it takes for an MCA
- * to surface is processor implementation specific. This code
- * is sufficient on Itanium through the Montvale processor family.
- * It may need to be adjusted for future processor implementations.
- *
- * extern int xp_nofault_PIOR(void *remote_register);
- */
-
- .global xp_nofault_PIOR
-xp_nofault_PIOR:
- mov r8=r0 // Stage a success return value
- ld8.acq r9=[r32];; // PIO Read the specified register
- adds r9=1,r9;; // Add to force consumption
- srlz.i;; // Allow time for MCA to surface
- br.ret.sptk.many b0;; // Return success
-
- .global xp_error_PIOR
-xp_error_PIOR:
- mov r8=1 // Return value of 1
- br.ret.sptk.many b0;; // Return failure
diff --git a/drivers/misc/sgi-xp/xp_sn2.c b/drivers/misc/sgi-xp/xp_sn2.c
deleted file mode 100644
index d8e463f87241..000000000000
--- a/drivers/misc/sgi-xp/xp_sn2.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.
- */
-
-/*
- * Cross Partition (XP) sn2-based functions.
- *
- * Architecture specific implementation of common functions.
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <asm/sn/bte.h>
-#include <asm/sn/sn_sal.h>
-#include "xp.h"
-
-/*
- * The export of xp_nofault_PIOR needs to happen here since it is defined
- * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is
- * defined here.
- */
-EXPORT_SYMBOL_GPL(xp_nofault_PIOR);
-
-u64 xp_nofault_PIOR_target;
-EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target);
-
-/*
- * Register a nofault code region which performs a cross-partition PIO read.
- * If the PIO read times out, the MCA handler will consume the error and
- * return to a kernel-provided instruction to indicate an error. This PIO read
- * exists because it is guaranteed to timeout if the destination is down
- * (amo operations do not timeout on at least some CPUs on Shubs <= v1.2,
- * which unfortunately we have to work around).
- */
-static enum xp_retval
-xp_register_nofault_code_sn2(void)
-{
- int ret;
- u64 func_addr;
- u64 err_func_addr;
-
- func_addr = *(u64 *)xp_nofault_PIOR;
- err_func_addr = *(u64 *)xp_error_PIOR;
- ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr,
- 1, 1);
- if (ret != 0) {
- dev_err(xp, "can't register nofault code, error=%d\n", ret);
- return xpSalError;
- }
- /*
- * Setup the nofault PIO read target. (There is no special reason why
- * SH_IPI_ACCESS was selected.)
- */
- if (is_shub1())
- xp_nofault_PIOR_target = SH1_IPI_ACCESS;
- else if (is_shub2())
- xp_nofault_PIOR_target = SH2_IPI_ACCESS0;
-
- return xpSuccess;
-}
-
-static void
-xp_unregister_nofault_code_sn2(void)
-{
- u64 func_addr = *(u64 *)xp_nofault_PIOR;
- u64 err_func_addr = *(u64 *)xp_error_PIOR;
-
- /* unregister the PIO read nofault code region */
- (void)sn_register_nofault_code(func_addr, err_func_addr,
- err_func_addr, 1, 0);
-}
-
-/*
- * Convert a virtual memory address to a physical memory address.
- */
-static unsigned long
-xp_pa_sn2(void *addr)
-{
- return __pa(addr);
-}
-
-/*
- * Convert a global physical to a socket physical address.
- */
-static unsigned long
-xp_socket_pa_sn2(unsigned long gpa)
-{
- return gpa;
-}
-
-/*
- * Wrapper for bte_copy().
- *
- * dst_pa - physical address of the destination of the transfer.
- * src_pa - physical address of the source of the transfer.
- * len - number of bytes to transfer from source to destination.
- *
- * Note: xp_remote_memcpy_sn2() should never be called while holding a spinlock.
- */
-static enum xp_retval
-xp_remote_memcpy_sn2(unsigned long dst_pa, const unsigned long src_pa,
- size_t len)
-{
- bte_result_t ret;
-
- ret = bte_copy(src_pa, dst_pa, len, (BTE_NOTIFY | BTE_WACQUIRE), NULL);
- if (ret == BTE_SUCCESS)
- return xpSuccess;
-
- if (is_shub2()) {
- dev_err(xp, "bte_copy() on shub2 failed, error=0x%x dst_pa="
- "0x%016lx src_pa=0x%016lx len=%ld\\n", ret, dst_pa,
- src_pa, len);
- } else {
- dev_err(xp, "bte_copy() failed, error=%d dst_pa=0x%016lx "
- "src_pa=0x%016lx len=%ld\\n", ret, dst_pa, src_pa, len);
- }
-
- return xpBteCopyError;
-}
-
-static int
-xp_cpu_to_nasid_sn2(int cpuid)
-{
- return cpuid_to_nasid(cpuid);
-}
-
-static enum xp_retval
-xp_expand_memprotect_sn2(unsigned long phys_addr, unsigned long size)
-{
- u64 nasid_array = 0;
- int ret;
-
- ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
- &nasid_array);
- if (ret != 0) {
- dev_err(xp, "sn_change_memprotect(,, "
- "SN_MEMPROT_ACCESS_CLASS_1,) failed ret=%d\n", ret);
- return xpSalError;
- }
- return xpSuccess;
-}
-
-static enum xp_retval
-xp_restrict_memprotect_sn2(unsigned long phys_addr, unsigned long size)
-{
- u64 nasid_array = 0;
- int ret;
-
- ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
- &nasid_array);
- if (ret != 0) {
- dev_err(xp, "sn_change_memprotect(,, "
- "SN_MEMPROT_ACCESS_CLASS_0,) failed ret=%d\n", ret);
- return xpSalError;
- }
- return xpSuccess;
-}
-
-enum xp_retval
-xp_init_sn2(void)
-{
- BUG_ON(!is_shub());
-
- xp_max_npartitions = XP_MAX_NPARTITIONS_SN2;
- xp_partition_id = sn_partition_id;
- xp_region_size = sn_region_size;
-
- xp_pa = xp_pa_sn2;
- xp_socket_pa = xp_socket_pa_sn2;
- xp_remote_memcpy = xp_remote_memcpy_sn2;
- xp_cpu_to_nasid = xp_cpu_to_nasid_sn2;
- xp_expand_memprotect = xp_expand_memprotect_sn2;
- xp_restrict_memprotect = xp_restrict_memprotect_sn2;
-
- return xp_register_nofault_code_sn2();
-}
-
-void
-xp_exit_sn2(void)
-{
- BUG_ON(!is_shub());
-
- xp_unregister_nofault_code_sn2();
-}
-
diff --git a/drivers/misc/sgi-xp/xp_uv.c b/drivers/misc/sgi-xp/xp_uv.c
index a0d093274dc0..f15a9f2ac1dd 100644
--- a/drivers/misc/sgi-xp/xp_uv.c
+++ b/drivers/misc/sgi-xp/xp_uv.c
@@ -17,7 +17,7 @@
#include <asm/uv/uv_hub.h>
#if defined CONFIG_X86_64
#include <asm/uv/bios.h>
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
#include <asm/sn/sn_sal.h>
#endif
#include "../sgi-gru/grukservices.h"
@@ -99,7 +99,7 @@ xp_expand_memprotect_uv(unsigned long phys_addr, unsigned long size)
return xpBiosError;
}
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
u64 nasid_array;
ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_1,
@@ -129,7 +129,7 @@ xp_restrict_memprotect_uv(unsigned long phys_addr, unsigned long size)
return xpBiosError;
}
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
u64 nasid_array;
ret = sn_change_memprotect(phys_addr, size, SN_MEMPROT_ACCESS_CLASS_0,
@@ -151,9 +151,10 @@ xp_init_uv(void)
BUG_ON(!is_uv());
xp_max_npartitions = XP_MAX_NPARTITIONS_UV;
+#ifdef CONFIG_X86
xp_partition_id = sn_partition_id;
xp_region_size = sn_region_size;
-
+#endif
xp_pa = xp_pa_uv;
xp_socket_pa = xp_socket_pa_uv;
xp_remote_memcpy = xp_remote_memcpy_uv;
diff --git a/drivers/misc/sgi-xp/xpc.h b/drivers/misc/sgi-xp/xpc.h
index b94d5f767703..71db60edff65 100644
--- a/drivers/misc/sgi-xp/xpc.h
+++ b/drivers/misc/sgi-xp/xpc.h
@@ -71,14 +71,10 @@
* 'SAL_nasids_size'. (Local partition's mask pointers are xpc_part_nasids
* and xpc_mach_nasids.)
*
- * vars (ia64-sn2 only)
- * vars part (ia64-sn2 only)
- *
* Immediately following the mach_nasids mask are the XPC variables
* required by other partitions. First are those that are generic to all
* partitions (vars), followed on the next available cacheline by those
* which are partition specific (vars part). These are setup by XPC.
- * (Local partition's vars pointers are xpc_vars and xpc_vars_part.)
*
* Note: Until 'ts_jiffies' is set non-zero, the partition XPC code has not been
* initialized.
@@ -93,9 +89,6 @@ struct xpc_rsvd_page {
unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */
union {
struct {
- unsigned long vars_pa; /* phys addr */
- } sn2;
- struct {
unsigned long heartbeat_gpa; /* phys addr */
unsigned long activate_gru_mq_desc_gpa; /* phys addr */
} uv;
@@ -106,84 +99,14 @@ struct xpc_rsvd_page {
#define XPC_RP_VERSION _XPC_VERSION(3, 0) /* version 3.0 of the reserved page */
-/*
- * Define the structures by which XPC variables can be exported to other
- * partitions. (There are two: struct xpc_vars and struct xpc_vars_part)
- */
-
-/*
- * The following structure describes the partition generic variables
- * needed by other partitions in order to properly initialize.
- *
- * struct xpc_vars version number also applies to struct xpc_vars_part.
- * Changes to either structure and/or related functionality should be
- * reflected by incrementing either the major or minor version numbers
- * of struct xpc_vars.
- */
-struct xpc_vars_sn2 {
- u8 version;
- u64 heartbeat;
- DECLARE_BITMAP(heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2);
- u64 heartbeat_offline; /* if 0, heartbeat should be changing */
- int activate_IRQ_nasid;
- int activate_IRQ_phys_cpuid;
- unsigned long vars_part_pa;
- unsigned long amos_page_pa;/* paddr of page of amos from MSPEC driver */
- struct amo *amos_page; /* vaddr of page of amos from MSPEC driver */
-};
-
-#define XPC_V_VERSION _XPC_VERSION(3, 1) /* version 3.1 of the cross vars */
-
-/*
- * The following structure describes the per partition specific variables.
- *
- * An array of these structures, one per partition, will be defined. As a
- * partition becomes active XPC will copy the array entry corresponding to
- * itself from that partition. It is desirable that the size of this structure
- * evenly divides into a 128-byte cacheline, such that none of the entries in
- * this array crosses a 128-byte cacheline boundary. As it is now, each entry
- * occupies 64-bytes.
- */
-struct xpc_vars_part_sn2 {
- u64 magic;
-
- unsigned long openclose_args_pa; /* phys addr of open and close args */
- unsigned long GPs_pa; /* physical address of Get/Put values */
-
- unsigned long chctl_amo_pa; /* physical address of chctl flags' amo */
-
- int notify_IRQ_nasid; /* nasid of where to send notify IRQs */
- int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */
-
- u8 nchannels; /* #of defined channels supported */
-
- u8 reserved[23]; /* pad to a full 64 bytes */
-};
-
-/*
- * The vars_part MAGIC numbers play a part in the first contact protocol.
- *
- * MAGIC1 indicates that the per partition specific variables for a remote
- * partition have been initialized by this partition.
- *
- * MAGIC2 indicates that this partition has pulled the remote partititions
- * per partition variables that pertain to this partition.
- */
-#define XPC_VP_MAGIC1_SN2 0x0053524156435058L /* 'XPCVARS\0'L (little endian) */
-#define XPC_VP_MAGIC2_SN2 0x0073726176435058L /* 'XPCvars\0'L (little endian) */
-
/* the reserved page sizes and offsets */
#define XPC_RP_HEADER_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))
-#define XPC_RP_VARS_SIZE L1_CACHE_ALIGN(sizeof(struct xpc_vars_sn2))
#define XPC_RP_PART_NASIDS(_rp) ((unsigned long *)((u8 *)(_rp) + \
XPC_RP_HEADER_SIZE))
#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + \
xpc_nasid_mask_nlongs)
-#define XPC_RP_VARS(_rp) ((struct xpc_vars_sn2 *) \
- (XPC_RP_MACH_NASIDS(_rp) + \
- xpc_nasid_mask_nlongs))
/*
@@ -298,17 +221,6 @@ struct xpc_activate_mq_msg_chctl_opencomplete_uv {
#define XPC_UNPACK_ARG2(_args) ((((u64)_args) >> 32) & 0xffffffff)
/*
- * Define a Get/Put value pair (pointers) used with a message queue.
- */
-struct xpc_gp_sn2 {
- s64 get; /* Get value */
- s64 put; /* Put value */
-};
-
-#define XPC_GP_SIZE \
- L1_CACHE_ALIGN(sizeof(struct xpc_gp_sn2) * XPC_MAX_NCHANNELS)
-
-/*
* Define a structure that contains arguments associated with opening and
* closing a channel.
*/
@@ -341,30 +253,6 @@ struct xpc_fifo_head_uv {
};
/*
- * Define a sn2 styled message.
- *
- * A user-defined message resides in the payload area. The max size of the
- * payload is defined by the user via xpc_connect().
- *
- * The size of a message entry (within a message queue) must be a 128-byte
- * cacheline sized multiple in order to facilitate the BTE transfer of messages
- * from one message queue to another.
- */
-struct xpc_msg_sn2 {
- u8 flags; /* FOR XPC INTERNAL USE ONLY */
- u8 reserved[7]; /* FOR XPC INTERNAL USE ONLY */
- s64 number; /* FOR XPC INTERNAL USE ONLY */
-
- u64 payload; /* user defined portion of message */
-};
-
-/* struct xpc_msg_sn2 flags */
-
-#define XPC_M_SN2_DONE 0x01 /* msg has been received/consumed */
-#define XPC_M_SN2_READY 0x02 /* msg is ready to be sent */
-#define XPC_M_SN2_INTERRUPT 0x04 /* send interrupt when msg consumed */
-
-/*
* The format of a uv XPC notify_mq GRU message is as follows:
*
* A user-defined message resides in the payload area. The max size of the
@@ -390,20 +278,6 @@ struct xpc_notify_mq_msg_uv {
unsigned long payload;
};
-/*
- * Define sn2's notify entry.
- *
- * This is used to notify a message's sender that their message was received
- * and consumed by the intended recipient.
- */
-struct xpc_notify_sn2 {
- u8 type; /* type of notification */
-
- /* the following two fields are only used if type == XPC_N_CALL */
- xpc_notify_func func; /* user's notify function */
- void *key; /* pointer to user's key */
-};
-
/* struct xpc_notify_sn2 type of notification */
#define XPC_N_CALL 0x01 /* notify function provided by user */
@@ -431,102 +305,6 @@ struct xpc_send_msg_slot_uv {
* of these structures for each potential channel connection to that partition.
*/
-/*
- * The following is sn2 only.
- *
- * Each channel structure manages two message queues (circular buffers).
- * They are allocated at the time a channel connection is made. One of
- * these message queues (local_msgqueue) holds the locally created messages
- * that are destined for the remote partition. The other of these message
- * queues (remote_msgqueue) is a locally cached copy of the remote partition's
- * own local_msgqueue.
- *
- * The following is a description of the Get/Put pointers used to manage these
- * two message queues. Consider the local_msgqueue to be on one partition
- * and the remote_msgqueue to be its cached copy on another partition. A
- * description of what each of the lettered areas contains is included.
- *
- *
- * local_msgqueue remote_msgqueue
- *
- * |/////////| |/////////|
- * w_remote_GP.get --> +---------+ |/////////|
- * | F | |/////////|
- * remote_GP.get --> +---------+ +---------+ <-- local_GP->get
- * | | | |
- * | | | E |
- * | | | |
- * | | +---------+ <-- w_local_GP.get
- * | B | |/////////|
- * | | |////D////|
- * | | |/////////|
- * | | +---------+ <-- w_remote_GP.put
- * | | |////C////|
- * local_GP->put --> +---------+ +---------+ <-- remote_GP.put
- * | | |/////////|
- * | A | |/////////|
- * | | |/////////|
- * w_local_GP.put --> +---------+ |/////////|
- * |/////////| |/////////|
- *
- *
- * ( remote_GP.[get|put] are cached copies of the remote
- * partition's local_GP->[get|put], and thus their values can
- * lag behind their counterparts on the remote partition. )
- *
- *
- * A - Messages that have been allocated, but have not yet been sent to the
- * remote partition.
- *
- * B - Messages that have been sent, but have not yet been acknowledged by the
- * remote partition as having been received.
- *
- * C - Area that needs to be prepared for the copying of sent messages, by
- * the clearing of the message flags of any previously received messages.
- *
- * D - Area into which sent messages are to be copied from the remote
- * partition's local_msgqueue and then delivered to their intended
- * recipients. [ To allow for a multi-message copy, another pointer
- * (next_msg_to_pull) has been added to keep track of the next message
- * number needing to be copied (pulled). It chases after w_remote_GP.put.
- * Any messages lying between w_local_GP.get and next_msg_to_pull have
- * been copied and are ready to be delivered. ]
- *
- * E - Messages that have been copied and delivered, but have not yet been
- * acknowledged by the recipient as having been received.
- *
- * F - Messages that have been acknowledged, but XPC has not yet notified the
- * sender that the message was received by its intended recipient.
- * This is also an area that needs to be prepared for the allocating of
- * new messages, by the clearing of the message flags of the acknowledged
- * messages.
- */
-
-struct xpc_channel_sn2 {
- struct xpc_openclose_args *local_openclose_args; /* args passed on */
- /* opening or closing of channel */
-
- void *local_msgqueue_base; /* base address of kmalloc'd space */
- struct xpc_msg_sn2 *local_msgqueue; /* local message queue */
- void *remote_msgqueue_base; /* base address of kmalloc'd space */
- struct xpc_msg_sn2 *remote_msgqueue; /* cached copy of remote */
- /* partition's local message queue */
- unsigned long remote_msgqueue_pa; /* phys addr of remote partition's */
- /* local message queue */
-
- struct xpc_notify_sn2 *notify_queue;/* notify queue for messages sent */
-
- /* various flavors of local and remote Get/Put values */
-
- struct xpc_gp_sn2 *local_GP; /* local Get/Put values */
- struct xpc_gp_sn2 remote_GP; /* remote Get/Put values */
- struct xpc_gp_sn2 w_local_GP; /* working local Get/Put values */
- struct xpc_gp_sn2 w_remote_GP; /* working remote Get/Put values */
- s64 next_msg_to_pull; /* Put value of next msg to pull */
-
- struct mutex msg_to_pull_mutex; /* next msg to pull serialization */
-};
-
struct xpc_channel_uv {
void *cached_notify_gru_mq_desc; /* remote partition's notify mq's */
/* gru mq descriptor */
@@ -579,7 +357,6 @@ struct xpc_channel {
wait_queue_head_t idle_wq; /* idle kthread wait queue */
union {
- struct xpc_channel_sn2 sn2;
struct xpc_channel_uv uv;
} sn;
@@ -666,43 +443,6 @@ xpc_any_msg_chctl_flags_set(union xpc_channel_ctl_flags *chctl)
return 0;
}
-/*
- * Manage channels on a partition basis. There is one of these structures
- * for each partition (a partition will never utilize the structure that
- * represents itself).
- */
-
-struct xpc_partition_sn2 {
- unsigned long remote_amos_page_pa; /* paddr of partition's amos page */
- int activate_IRQ_nasid; /* active partition's act/deact nasid */
- int activate_IRQ_phys_cpuid; /* active part's act/deact phys cpuid */
-
- unsigned long remote_vars_pa; /* phys addr of partition's vars */
- unsigned long remote_vars_part_pa; /* paddr of partition's vars part */
- u8 remote_vars_version; /* version# of partition's vars */
-
- void *local_GPs_base; /* base address of kmalloc'd space */
- struct xpc_gp_sn2 *local_GPs; /* local Get/Put values */
- void *remote_GPs_base; /* base address of kmalloc'd space */
- struct xpc_gp_sn2 *remote_GPs; /* copy of remote partition's local */
- /* Get/Put values */
- unsigned long remote_GPs_pa; /* phys addr of remote partition's local */
- /* Get/Put values */
-
- void *local_openclose_args_base; /* base address of kmalloc'd space */
- struct xpc_openclose_args *local_openclose_args; /* local's args */
- unsigned long remote_openclose_args_pa; /* phys addr of remote's args */
-
- int notify_IRQ_nasid; /* nasid of where to send notify IRQs */
- int notify_IRQ_phys_cpuid; /* CPUID of where to send notify IRQs */
- char notify_IRQ_owner[8]; /* notify IRQ's owner's name */
-
- struct amo *remote_chctl_amo_va; /* addr of remote chctl flags' amo */
- struct amo *local_chctl_amo_va; /* address of chctl flags' amo */
-
- struct timer_list dropped_notify_IRQ_timer; /* dropped IRQ timer */
-};
-
struct xpc_partition_uv {
unsigned long heartbeat_gpa; /* phys addr of partition's heartbeat */
struct xpc_heartbeat_uv cached_heartbeat; /* cached copy of */
@@ -774,7 +514,6 @@ struct xpc_partition {
wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */
union {
- struct xpc_partition_sn2 sn2;
struct xpc_partition_uv uv;
} sn;
@@ -854,14 +593,6 @@ struct xpc_arch_operations {
#define XPC_P_SS_WTEARDOWN 0x02 /* waiting to teardown infrastructure */
#define XPC_P_SS_TORNDOWN 0x03 /* infrastructure is torndown */
-/*
- * struct xpc_partition_sn2's dropped notify IRQ timer is set to wait the
- * following interval #of seconds before checking for dropped notify IRQs.
- * These can occur whenever an IRQ's associated amo write doesn't complete
- * until after the IRQ was received.
- */
-#define XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL (0.25 * HZ)
-
/* number of seconds to wait for other partitions to disengage */
#define XPC_DISENGAGE_DEFAULT_TIMELIMIT 90
@@ -888,10 +619,6 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int);
extern void xpc_create_kthreads(struct xpc_channel *, int, int);
extern void xpc_disconnect_wait(int);
-/* found in xpc_sn2.c */
-extern int xpc_init_sn2(void);
-extern void xpc_exit_sn2(void);
-
/* found in xpc_uv.c */
extern int xpc_init_uv(void);
extern void xpc_exit_uv(void);
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index 83fc748a91a7..79a963105983 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -279,13 +279,6 @@ xpc_hb_checker(void *ignore)
dev_dbg(xpc_part, "checking remote heartbeats\n");
xpc_check_remote_hb();
-
- /*
- * On sn2 we need to periodically recheck to ensure no
- * IRQ/amo pairs have been missed.
- */
- if (is_shub())
- force_IRQ = 1;
}
/* check for outstanding IRQs */
@@ -1050,9 +1043,7 @@ xpc_do_exit(enum xp_retval reason)
xpc_teardown_partitions();
- if (is_shub())
- xpc_exit_sn2();
- else if (is_uv())
+ if (is_uv())
xpc_exit_uv();
}
@@ -1235,21 +1226,7 @@ xpc_init(void)
dev_set_name(xpc_part, "part");
dev_set_name(xpc_chan, "chan");
- if (is_shub()) {
- /*
- * The ia64-sn2 architecture supports at most 64 partitions.
- * And the inability to unregister remote amos restricts us
- * further to only support exactly 64 partitions on this
- * architecture, no less.
- */
- if (xp_max_npartitions != 64) {
- dev_err(xpc_part, "max #of partitions not set to 64\n");
- ret = -EINVAL;
- } else {
- ret = xpc_init_sn2();
- }
-
- } else if (is_uv()) {
+ if (is_uv()) {
ret = xpc_init_uv();
} else {
@@ -1335,9 +1312,7 @@ out_2:
xpc_teardown_partitions();
out_1:
- if (is_shub())
- xpc_exit_sn2();
- else if (is_uv())
+ if (is_uv())
xpc_exit_uv();
return ret;
}
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index 782ce95d3f17..21a04bc97d40 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -93,10 +93,6 @@ xpc_get_rsvd_page_pa(int nasid)
if (ret != xpNeedMoreInfo)
break;
- /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */
- if (is_shub())
- len = L1_CACHE_ALIGN(len);
-
if (len > buf_len) {
kfree(buf_base);
buf_len = L1_CACHE_ALIGN(len);
@@ -452,7 +448,6 @@ xpc_discovery(void)
case 32:
max_regions *= 2;
region_size = 16;
- DBUG_ON(!is_shub2());
}
}
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c
deleted file mode 100644
index 0ae69b9390ce..000000000000
--- a/drivers/misc/sgi-xp/xpc_sn2.c
+++ /dev/null
@@ -1,2459 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2008-2009 Silicon Graphics, Inc. All Rights Reserved.
- */
-
-/*
- * Cross Partition Communication (XPC) sn2-based functions.
- *
- * Architecture specific implementation of common functions.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <asm/uncached.h>
-#include <asm/sn/mspec.h>
-#include <asm/sn/sn_sal.h>
-#include "xpc.h"
-
-/*
- * Define the number of u64s required to represent all the C-brick nasids
- * as a bitmap. The cross-partition kernel modules deal only with
- * C-brick nasids, thus the need for bitmaps which don't account for
- * odd-numbered (non C-brick) nasids.
- */
-#define XPC_MAX_PHYSNODES_SN2 (MAX_NUMALINK_NODES / 2)
-#define XP_NASID_MASK_BYTES_SN2 ((XPC_MAX_PHYSNODES_SN2 + 7) / 8)
-#define XP_NASID_MASK_WORDS_SN2 ((XPC_MAX_PHYSNODES_SN2 + 63) / 64)
-
-/*
- * Memory for XPC's amo variables is allocated by the MSPEC driver. These
- * pages are located in the lowest granule. The lowest granule uses 4k pages
- * for cached references and an alternate TLB handler to never provide a
- * cacheable mapping for the entire region. This will prevent speculative
- * reading of cached copies of our lines from being issued which will cause
- * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64
- * amo variables (based on XP_MAX_NPARTITIONS_SN2) to identify the senders of
- * NOTIFY IRQs, 128 amo variables (based on XP_NASID_MASK_WORDS_SN2) to identify
- * the senders of ACTIVATE IRQs, 1 amo variable to identify which remote
- * partitions (i.e., XPCs) consider themselves currently engaged with the
- * local XPC and 1 amo variable to request partition deactivation.
- */
-#define XPC_NOTIFY_IRQ_AMOS_SN2 0
-#define XPC_ACTIVATE_IRQ_AMOS_SN2 (XPC_NOTIFY_IRQ_AMOS_SN2 + \
- XP_MAX_NPARTITIONS_SN2)
-#define XPC_ENGAGED_PARTITIONS_AMO_SN2 (XPC_ACTIVATE_IRQ_AMOS_SN2 + \
- XP_NASID_MASK_WORDS_SN2)
-#define XPC_DEACTIVATE_REQUEST_AMO_SN2 (XPC_ENGAGED_PARTITIONS_AMO_SN2 + 1)
-
-/*
- * Buffer used to store a local copy of portions of a remote partition's
- * reserved page (either its header and part_nasids mask, or its vars).
- */
-static void *xpc_remote_copy_buffer_base_sn2;
-static char *xpc_remote_copy_buffer_sn2;
-
-static struct xpc_vars_sn2 *xpc_vars_sn2;
-static struct xpc_vars_part_sn2 *xpc_vars_part_sn2;
-
-static int
-xpc_setup_partitions_sn2(void)
-{
- /* nothing needs to be done */
- return 0;
-}
-
-static void
-xpc_teardown_partitions_sn2(void)
-{
- /* nothing needs to be done */
-}
-
-/* SH_IPI_ACCESS shub register value on startup */
-static u64 xpc_sh1_IPI_access_sn2;
-static u64 xpc_sh2_IPI_access0_sn2;
-static u64 xpc_sh2_IPI_access1_sn2;
-static u64 xpc_sh2_IPI_access2_sn2;
-static u64 xpc_sh2_IPI_access3_sn2;
-
-/*
- * Change protections to allow IPI operations.
- */
-static void
-xpc_allow_IPI_ops_sn2(void)
-{
- int node;
- int nasid;
-
- /* !!! The following should get moved into SAL. */
- if (is_shub2()) {
- xpc_sh2_IPI_access0_sn2 =
- (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS0));
- xpc_sh2_IPI_access1_sn2 =
- (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS1));
- xpc_sh2_IPI_access2_sn2 =
- (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS2));
- xpc_sh2_IPI_access3_sn2 =
- (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH2_IPI_ACCESS3));
-
- for_each_online_node(node) {
- nasid = cnodeid_to_nasid(node);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0),
- -1UL);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1),
- -1UL);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2),
- -1UL);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3),
- -1UL);
- }
- } else {
- xpc_sh1_IPI_access_sn2 =
- (u64)HUB_L((u64 *)LOCAL_MMR_ADDR(SH1_IPI_ACCESS));
-
- for_each_online_node(node) {
- nasid = cnodeid_to_nasid(node);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS),
- -1UL);
- }
- }
-}
-
-/*
- * Restrict protections to disallow IPI operations.
- */
-static void
-xpc_disallow_IPI_ops_sn2(void)
-{
- int node;
- int nasid;
-
- /* !!! The following should get moved into SAL. */
- if (is_shub2()) {
- for_each_online_node(node) {
- nasid = cnodeid_to_nasid(node);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS0),
- xpc_sh2_IPI_access0_sn2);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS1),
- xpc_sh2_IPI_access1_sn2);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS2),
- xpc_sh2_IPI_access2_sn2);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH2_IPI_ACCESS3),
- xpc_sh2_IPI_access3_sn2);
- }
- } else {
- for_each_online_node(node) {
- nasid = cnodeid_to_nasid(node);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid, SH1_IPI_ACCESS),
- xpc_sh1_IPI_access_sn2);
- }
- }
-}
-
-/*
- * The following set of functions are used for the sending and receiving of
- * IRQs (also known as IPIs). There are two flavors of IRQs, one that is
- * associated with partition activity (SGI_XPC_ACTIVATE) and the other that
- * is associated with channel activity (SGI_XPC_NOTIFY).
- */
-
-static u64
-xpc_receive_IRQ_amo_sn2(struct amo *amo)
-{
- return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_CLEAR);
-}
-
-static enum xp_retval
-xpc_send_IRQ_sn2(struct amo *amo, u64 flag, int nasid, int phys_cpuid,
- int vector)
-{
- int ret = 0;
- unsigned long irq_flags;
-
- local_irq_save(irq_flags);
-
- FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR, flag);
- sn_send_IPI_phys(nasid, phys_cpuid, vector, 0);
-
- /*
- * We must always use the nofault function regardless of whether we
- * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
- * didn't, we'd never know that the other partition is down and would
- * keep sending IRQs and amos to it until the heartbeat times out.
- */
- ret = xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->variable),
- xp_nofault_PIOR_target));
-
- local_irq_restore(irq_flags);
-
- return (ret == 0) ? xpSuccess : xpPioReadError;
-}
-
-static struct amo *
-xpc_init_IRQ_amo_sn2(int index)
-{
- struct amo *amo = xpc_vars_sn2->amos_page + index;
-
- (void)xpc_receive_IRQ_amo_sn2(amo); /* clear amo variable */
- return amo;
-}
-
-/*
- * Functions associated with SGI_XPC_ACTIVATE IRQ.
- */
-
-/*
- * Notify the heartbeat check thread that an activate IRQ has been received.
- */
-static irqreturn_t
-xpc_handle_activate_IRQ_sn2(int irq, void *dev_id)
-{
- unsigned long irq_flags;
-
- spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
- xpc_activate_IRQ_rcvd++;
- spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-
- wake_up_interruptible(&xpc_activate_IRQ_wq);
- return IRQ_HANDLED;
-}
-
-/*
- * Flag the appropriate amo variable and send an IRQ to the specified node.
- */
-static void
-xpc_send_activate_IRQ_sn2(unsigned long amos_page_pa, int from_nasid,
- int to_nasid, int to_phys_cpuid)
-{
- struct amo *amos = (struct amo *)__va(amos_page_pa +
- (XPC_ACTIVATE_IRQ_AMOS_SN2 *
- sizeof(struct amo)));
-
- (void)xpc_send_IRQ_sn2(&amos[BIT_WORD(from_nasid / 2)],
- BIT_MASK(from_nasid / 2), to_nasid,
- to_phys_cpuid, SGI_XPC_ACTIVATE);
-}
-
-static void
-xpc_send_local_activate_IRQ_sn2(int from_nasid)
-{
- unsigned long irq_flags;
- struct amo *amos = (struct amo *)__va(xpc_vars_sn2->amos_page_pa +
- (XPC_ACTIVATE_IRQ_AMOS_SN2 *
- sizeof(struct amo)));
-
- /* fake the sending and receipt of an activate IRQ from remote nasid */
- FETCHOP_STORE_OP(TO_AMO((u64)&amos[BIT_WORD(from_nasid / 2)].variable),
- FETCHOP_OR, BIT_MASK(from_nasid / 2));
-
- spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
- xpc_activate_IRQ_rcvd++;
- spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-
- wake_up_interruptible(&xpc_activate_IRQ_wq);
-}
-
-/*
- * Functions associated with SGI_XPC_NOTIFY IRQ.
- */
-
-/*
- * Check to see if any chctl flags were sent from the specified partition.
- */
-static void
-xpc_check_for_sent_chctl_flags_sn2(struct xpc_partition *part)
-{
- union xpc_channel_ctl_flags chctl;
- unsigned long irq_flags;
-
- chctl.all_flags = xpc_receive_IRQ_amo_sn2(part->sn.sn2.
- local_chctl_amo_va);
- if (chctl.all_flags == 0)
- return;
-
- spin_lock_irqsave(&part->chctl_lock, irq_flags);
- part->chctl.all_flags |= chctl.all_flags;
- spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
-
- dev_dbg(xpc_chan, "received notify IRQ from partid=%d, chctl.all_flags="
- "0x%llx\n", XPC_PARTID(part), chctl.all_flags);
-
- xpc_wakeup_channel_mgr(part);
-}
-
-/*
- * Handle the receipt of a SGI_XPC_NOTIFY IRQ by seeing whether the specified
- * partition actually sent it. Since SGI_XPC_NOTIFY IRQs may be shared by more
- * than one partition, we use an amo structure per partition to indicate
- * whether a partition has sent an IRQ or not. If it has, then wake up the
- * associated kthread to handle it.
- *
- * All SGI_XPC_NOTIFY IRQs received by XPC are the result of IRQs sent by XPC
- * running on other partitions.
- *
- * Noteworthy Arguments:
- *
- * irq - Interrupt ReQuest number. NOT USED.
- *
- * dev_id - partid of IRQ's potential sender.
- */
-static irqreturn_t
-xpc_handle_notify_IRQ_sn2(int irq, void *dev_id)
-{
- short partid = (short)(u64)dev_id;
- struct xpc_partition *part = &xpc_partitions[partid];
-
- DBUG_ON(partid < 0 || partid >= XP_MAX_NPARTITIONS_SN2);
-
- if (xpc_part_ref(part)) {
- xpc_check_for_sent_chctl_flags_sn2(part);
-
- xpc_part_deref(part);
- }
- return IRQ_HANDLED;
-}
-
-/*
- * Check to see if xpc_handle_notify_IRQ_sn2() dropped any IRQs on the floor
- * because the write to their associated amo variable completed after the IRQ
- * was received.
- */
-static void
-xpc_check_for_dropped_notify_IRQ_sn2(struct timer_list *t)
-{
- struct xpc_partition *part =
- from_timer(part, t, sn.sn2.dropped_notify_IRQ_timer);
-
- if (xpc_part_ref(part)) {
- xpc_check_for_sent_chctl_flags_sn2(part);
-
- t->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
- add_timer(t);
- xpc_part_deref(part);
- }
-}
-
-/*
- * Send a notify IRQ to the remote partition that is associated with the
- * specified channel.
- */
-static void
-xpc_send_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag,
- char *chctl_flag_string, unsigned long *irq_flags)
-{
- struct xpc_partition *part = &xpc_partitions[ch->partid];
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- union xpc_channel_ctl_flags chctl = { 0 };
- enum xp_retval ret;
-
- if (likely(part->act_state != XPC_P_AS_DEACTIVATING)) {
- chctl.flags[ch->number] = chctl_flag;
- ret = xpc_send_IRQ_sn2(part_sn2->remote_chctl_amo_va,
- chctl.all_flags,
- part_sn2->notify_IRQ_nasid,
- part_sn2->notify_IRQ_phys_cpuid,
- SGI_XPC_NOTIFY);
- dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
- chctl_flag_string, ch->partid, ch->number, ret);
- if (unlikely(ret != xpSuccess)) {
- if (irq_flags != NULL)
- spin_unlock_irqrestore(&ch->lock, *irq_flags);
- XPC_DEACTIVATE_PARTITION(part, ret);
- if (irq_flags != NULL)
- spin_lock_irqsave(&ch->lock, *irq_flags);
- }
- }
-}
-
-#define XPC_SEND_NOTIFY_IRQ_SN2(_ch, _ipi_f, _irq_f) \
- xpc_send_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f, _irq_f)
-
-/*
- * Make it look like the remote partition, which is associated with the
- * specified channel, sent us a notify IRQ. This faked IRQ will be handled
- * by xpc_check_for_dropped_notify_IRQ_sn2().
- */
-static void
-xpc_send_local_notify_IRQ_sn2(struct xpc_channel *ch, u8 chctl_flag,
- char *chctl_flag_string)
-{
- struct xpc_partition *part = &xpc_partitions[ch->partid];
- union xpc_channel_ctl_flags chctl = { 0 };
-
- chctl.flags[ch->number] = chctl_flag;
- FETCHOP_STORE_OP(TO_AMO((u64)&part->sn.sn2.local_chctl_amo_va->
- variable), FETCHOP_OR, chctl.all_flags);
- dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n",
- chctl_flag_string, ch->partid, ch->number);
-}
-
-#define XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(_ch, _ipi_f) \
- xpc_send_local_notify_IRQ_sn2(_ch, _ipi_f, #_ipi_f)
-
-static void
-xpc_send_chctl_closerequest_sn2(struct xpc_channel *ch,
- unsigned long *irq_flags)
-{
- struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;
-
- args->reason = ch->reason;
- XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREQUEST, irq_flags);
-}
-
-static void
-xpc_send_chctl_closereply_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
-{
- XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_CLOSEREPLY, irq_flags);
-}
-
-static void
-xpc_send_chctl_openrequest_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
-{
- struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;
-
- args->entry_size = ch->entry_size;
- args->local_nentries = ch->local_nentries;
- XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREQUEST, irq_flags);
-}
-
-static void
-xpc_send_chctl_openreply_sn2(struct xpc_channel *ch, unsigned long *irq_flags)
-{
- struct xpc_openclose_args *args = ch->sn.sn2.local_openclose_args;
-
- args->remote_nentries = ch->remote_nentries;
- args->local_nentries = ch->local_nentries;
- args->local_msgqueue_pa = xp_pa(ch->sn.sn2.local_msgqueue);
- XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENREPLY, irq_flags);
-}
-
-static void
-xpc_send_chctl_opencomplete_sn2(struct xpc_channel *ch,
- unsigned long *irq_flags)
-{
- XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_OPENCOMPLETE, irq_flags);
-}
-
-static void
-xpc_send_chctl_msgrequest_sn2(struct xpc_channel *ch)
-{
- XPC_SEND_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST, NULL);
-}
-
-static void
-xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch)
-{
- XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST);
-}
-
-static enum xp_retval
-xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch,
- unsigned long msgqueue_pa)
-{
- ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa;
- return xpSuccess;
-}
-
-/*
- * This next set of functions are used to keep track of when a partition is
- * potentially engaged in accessing memory belonging to another partition.
- */
-
-static void
-xpc_indicate_partition_engaged_sn2(struct xpc_partition *part)
-{
- unsigned long irq_flags;
- struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa +
- (XPC_ENGAGED_PARTITIONS_AMO_SN2 *
- sizeof(struct amo)));
-
- local_irq_save(irq_flags);
-
- /* set bit corresponding to our partid in remote partition's amo */
- FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR,
- BIT(sn_partition_id));
-
- /*
- * We must always use the nofault function regardless of whether we
- * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
- * didn't, we'd never know that the other partition is down and would
- * keep sending IRQs and amos to it until the heartbeat times out.
- */
- (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
- variable),
- xp_nofault_PIOR_target));
-
- local_irq_restore(irq_flags);
-}
-
-static void
-xpc_indicate_partition_disengaged_sn2(struct xpc_partition *part)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- unsigned long irq_flags;
- struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa +
- (XPC_ENGAGED_PARTITIONS_AMO_SN2 *
- sizeof(struct amo)));
-
- local_irq_save(irq_flags);
-
- /* clear bit corresponding to our partid in remote partition's amo */
- FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
- ~BIT(sn_partition_id));
-
- /*
- * We must always use the nofault function regardless of whether we
- * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
- * didn't, we'd never know that the other partition is down and would
- * keep sending IRQs and amos to it until the heartbeat times out.
- */
- (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
- variable),
- xp_nofault_PIOR_target));
-
- local_irq_restore(irq_flags);
-
- /*
- * Send activate IRQ to get other side to see that we've cleared our
- * bit in their engaged partitions amo.
- */
- xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa,
- cnodeid_to_nasid(0),
- part_sn2->activate_IRQ_nasid,
- part_sn2->activate_IRQ_phys_cpuid);
-}
-
-static void
-xpc_assume_partition_disengaged_sn2(short partid)
-{
- struct amo *amo = xpc_vars_sn2->amos_page +
- XPC_ENGAGED_PARTITIONS_AMO_SN2;
-
- /* clear bit(s) based on partid mask in our partition's amo */
- FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
- ~BIT(partid));
-}
-
-static int
-xpc_partition_engaged_sn2(short partid)
-{
- struct amo *amo = xpc_vars_sn2->amos_page +
- XPC_ENGAGED_PARTITIONS_AMO_SN2;
-
- /* our partition's amo variable ANDed with partid mask */
- return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) &
- BIT(partid)) != 0;
-}
-
-static int
-xpc_any_partition_engaged_sn2(void)
-{
- struct amo *amo = xpc_vars_sn2->amos_page +
- XPC_ENGAGED_PARTITIONS_AMO_SN2;
-
- /* our partition's amo variable */
- return FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) != 0;
-}
-
-/* original protection values for each node */
-static u64 xpc_prot_vec_sn2[MAX_NUMNODES];
-
-/*
- * Change protections to allow amo operations on non-Shub 1.1 systems.
- */
-static enum xp_retval
-xpc_allow_amo_ops_sn2(struct amo *amos_page)
-{
- enum xp_retval ret = xpSuccess;
-
- /*
- * On SHUB 1.1, we cannot call sn_change_memprotect() since the BIST
- * collides with memory operations. On those systems we call
- * xpc_allow_amo_ops_shub_wars_1_1_sn2() instead.
- */
- if (!enable_shub_wars_1_1())
- ret = xp_expand_memprotect(ia64_tpa((u64)amos_page), PAGE_SIZE);
-
- return ret;
-}
-
-/*
- * Change protections to allow amo operations on Shub 1.1 systems.
- */
-static void
-xpc_allow_amo_ops_shub_wars_1_1_sn2(void)
-{
- int node;
- int nasid;
-
- if (!enable_shub_wars_1_1())
- return;
-
- for_each_online_node(node) {
- nasid = cnodeid_to_nasid(node);
- /* save current protection values */
- xpc_prot_vec_sn2[node] =
- (u64)HUB_L((u64 *)GLOBAL_MMR_ADDR(nasid,
- SH1_MD_DQLP_MMR_DIR_PRIVEC0));
- /* open up everything */
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid,
- SH1_MD_DQLP_MMR_DIR_PRIVEC0),
- -1UL);
- HUB_S((u64 *)GLOBAL_MMR_ADDR(nasid,
- SH1_MD_DQRP_MMR_DIR_PRIVEC0),
- -1UL);
- }
-}
-
-static enum xp_retval
-xpc_get_partition_rsvd_page_pa_sn2(void *buf, u64 *cookie, unsigned long *rp_pa,
- size_t *len)
-{
- s64 status;
- enum xp_retval ret;
-
- status = sn_partition_reserved_page_pa((u64)buf, cookie,
- (u64 *)rp_pa, (u64 *)len);
- if (status == SALRET_OK)
- ret = xpSuccess;
- else if (status == SALRET_MORE_PASSES)
- ret = xpNeedMoreInfo;
- else
- ret = xpSalError;
-
- return ret;
-}
-
-
-static int
-xpc_setup_rsvd_page_sn2(struct xpc_rsvd_page *rp)
-{
- struct amo *amos_page;
- int i;
- int ret;
-
- xpc_vars_sn2 = XPC_RP_VARS(rp);
-
- rp->sn.sn2.vars_pa = xp_pa(xpc_vars_sn2);
-
- /* vars_part array follows immediately after vars */
- xpc_vars_part_sn2 = (struct xpc_vars_part_sn2 *)((u8 *)XPC_RP_VARS(rp) +
- XPC_RP_VARS_SIZE);
-
- /*
- * Before clearing xpc_vars_sn2, see if a page of amos had been
- * previously allocated. If not we'll need to allocate one and set
- * permissions so that cross-partition amos are allowed.
- *
- * The allocated amo page needs MCA reporting to remain disabled after
- * XPC has unloaded. To make this work, we keep a copy of the pointer
- * to this page (i.e., amos_page) in the struct xpc_vars_sn2 structure,
- * which is pointed to by the reserved page, and re-use that saved copy
- * on subsequent loads of XPC. This amo page is never freed, and its
- * memory protections are never restricted.
- */
- amos_page = xpc_vars_sn2->amos_page;
- if (amos_page == NULL) {
- amos_page = (struct amo *)TO_AMO(uncached_alloc_page(0, 1));
- if (amos_page == NULL) {
- dev_err(xpc_part, "can't allocate page of amos\n");
- return -ENOMEM;
- }
-
- /*
- * Open up amo-R/W to cpu. This is done on Shub 1.1 systems
- * when xpc_allow_amo_ops_shub_wars_1_1_sn2() is called.
- */
- ret = xpc_allow_amo_ops_sn2(amos_page);
- if (ret != xpSuccess) {
- dev_err(xpc_part, "can't allow amo operations\n");
- uncached_free_page(__IA64_UNCACHED_OFFSET |
- TO_PHYS((u64)amos_page), 1);
- return -EPERM;
- }
- }
-
- /* clear xpc_vars_sn2 */
- memset(xpc_vars_sn2, 0, sizeof(struct xpc_vars_sn2));
-
- xpc_vars_sn2->version = XPC_V_VERSION;
- xpc_vars_sn2->activate_IRQ_nasid = cpuid_to_nasid(0);
- xpc_vars_sn2->activate_IRQ_phys_cpuid = cpu_physical_id(0);
- xpc_vars_sn2->vars_part_pa = xp_pa(xpc_vars_part_sn2);
- xpc_vars_sn2->amos_page_pa = ia64_tpa((u64)amos_page);
- xpc_vars_sn2->amos_page = amos_page; /* save for next load of XPC */
-
- /* clear xpc_vars_part_sn2 */
- memset((u64 *)xpc_vars_part_sn2, 0, sizeof(struct xpc_vars_part_sn2) *
- XP_MAX_NPARTITIONS_SN2);
-
- /* initialize the activate IRQ related amo variables */
- for (i = 0; i < xpc_nasid_mask_nlongs; i++)
- (void)xpc_init_IRQ_amo_sn2(XPC_ACTIVATE_IRQ_AMOS_SN2 + i);
-
- /* initialize the engaged remote partitions related amo variables */
- (void)xpc_init_IRQ_amo_sn2(XPC_ENGAGED_PARTITIONS_AMO_SN2);
- (void)xpc_init_IRQ_amo_sn2(XPC_DEACTIVATE_REQUEST_AMO_SN2);
-
- return 0;
-}
-
-static int
-xpc_hb_allowed_sn2(short partid, void *heartbeating_to_mask)
-{
- return test_bit(partid, heartbeating_to_mask);
-}
-
-static void
-xpc_allow_hb_sn2(short partid)
-{
- DBUG_ON(xpc_vars_sn2 == NULL);
- set_bit(partid, xpc_vars_sn2->heartbeating_to_mask);
-}
-
-static void
-xpc_disallow_hb_sn2(short partid)
-{
- DBUG_ON(xpc_vars_sn2 == NULL);
- clear_bit(partid, xpc_vars_sn2->heartbeating_to_mask);
-}
-
-static void
-xpc_disallow_all_hbs_sn2(void)
-{
- DBUG_ON(xpc_vars_sn2 == NULL);
- bitmap_zero(xpc_vars_sn2->heartbeating_to_mask, xp_max_npartitions);
-}
-
-static void
-xpc_increment_heartbeat_sn2(void)
-{
- xpc_vars_sn2->heartbeat++;
-}
-
-static void
-xpc_offline_heartbeat_sn2(void)
-{
- xpc_increment_heartbeat_sn2();
- xpc_vars_sn2->heartbeat_offline = 1;
-}
-
-static void
-xpc_online_heartbeat_sn2(void)
-{
- xpc_increment_heartbeat_sn2();
- xpc_vars_sn2->heartbeat_offline = 0;
-}
-
-static void
-xpc_heartbeat_init_sn2(void)
-{
- DBUG_ON(xpc_vars_sn2 == NULL);
-
- bitmap_zero(xpc_vars_sn2->heartbeating_to_mask, XP_MAX_NPARTITIONS_SN2);
- xpc_online_heartbeat_sn2();
-}
-
-static void
-xpc_heartbeat_exit_sn2(void)
-{
- xpc_offline_heartbeat_sn2();
-}
-
-static enum xp_retval
-xpc_get_remote_heartbeat_sn2(struct xpc_partition *part)
-{
- struct xpc_vars_sn2 *remote_vars;
- enum xp_retval ret;
-
- remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2;
-
- /* pull the remote vars structure that contains the heartbeat */
- ret = xp_remote_memcpy(xp_pa(remote_vars),
- part->sn.sn2.remote_vars_pa,
- XPC_RP_VARS_SIZE);
- if (ret != xpSuccess)
- return ret;
-
- dev_dbg(xpc_part, "partid=%d, heartbeat=%lld, last_heartbeat=%lld, "
- "heartbeat_offline=%lld, HB_mask[0]=0x%lx\n", XPC_PARTID(part),
- remote_vars->heartbeat, part->last_heartbeat,
- remote_vars->heartbeat_offline,
- remote_vars->heartbeating_to_mask[0]);
-
- if ((remote_vars->heartbeat == part->last_heartbeat &&
- !remote_vars->heartbeat_offline) ||
- !xpc_hb_allowed_sn2(sn_partition_id,
- remote_vars->heartbeating_to_mask)) {
- ret = xpNoHeartbeat;
- } else {
- part->last_heartbeat = remote_vars->heartbeat;
- }
-
- return ret;
-}
-
-/*
- * Get a copy of the remote partition's XPC variables from the reserved page.
- *
- * remote_vars points to a buffer that is cacheline aligned for BTE copies and
- * assumed to be of size XPC_RP_VARS_SIZE.
- */
-static enum xp_retval
-xpc_get_remote_vars_sn2(unsigned long remote_vars_pa,
- struct xpc_vars_sn2 *remote_vars)
-{
- enum xp_retval ret;
-
- if (remote_vars_pa == 0)
- return xpVarsNotSet;
-
- /* pull over the cross partition variables */
- ret = xp_remote_memcpy(xp_pa(remote_vars), remote_vars_pa,
- XPC_RP_VARS_SIZE);
- if (ret != xpSuccess)
- return ret;
-
- if (XPC_VERSION_MAJOR(remote_vars->version) !=
- XPC_VERSION_MAJOR(XPC_V_VERSION)) {
- return xpBadVersion;
- }
-
- return xpSuccess;
-}
-
-static void
-xpc_request_partition_activation_sn2(struct xpc_rsvd_page *remote_rp,
- unsigned long remote_rp_pa, int nasid)
-{
- xpc_send_local_activate_IRQ_sn2(nasid);
-}
-
-static void
-xpc_request_partition_reactivation_sn2(struct xpc_partition *part)
-{
- xpc_send_local_activate_IRQ_sn2(part->sn.sn2.activate_IRQ_nasid);
-}
-
-static void
-xpc_request_partition_deactivation_sn2(struct xpc_partition *part)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- unsigned long irq_flags;
- struct amo *amo = (struct amo *)__va(part_sn2->remote_amos_page_pa +
- (XPC_DEACTIVATE_REQUEST_AMO_SN2 *
- sizeof(struct amo)));
-
- local_irq_save(irq_flags);
-
- /* set bit corresponding to our partid in remote partition's amo */
- FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_OR,
- BIT(sn_partition_id));
-
- /*
- * We must always use the nofault function regardless of whether we
- * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
- * didn't, we'd never know that the other partition is down and would
- * keep sending IRQs and amos to it until the heartbeat times out.
- */
- (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
- variable),
- xp_nofault_PIOR_target));
-
- local_irq_restore(irq_flags);
-
- /*
- * Send activate IRQ to get other side to see that we've set our
- * bit in their deactivate request amo.
- */
- xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa,
- cnodeid_to_nasid(0),
- part_sn2->activate_IRQ_nasid,
- part_sn2->activate_IRQ_phys_cpuid);
-}
-
-static void
-xpc_cancel_partition_deactivation_request_sn2(struct xpc_partition *part)
-{
- unsigned long irq_flags;
- struct amo *amo = (struct amo *)__va(part->sn.sn2.remote_amos_page_pa +
- (XPC_DEACTIVATE_REQUEST_AMO_SN2 *
- sizeof(struct amo)));
-
- local_irq_save(irq_flags);
-
- /* clear bit corresponding to our partid in remote partition's amo */
- FETCHOP_STORE_OP(TO_AMO((u64)&amo->variable), FETCHOP_AND,
- ~BIT(sn_partition_id));
-
- /*
- * We must always use the nofault function regardless of whether we
- * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
- * didn't, we'd never know that the other partition is down and would
- * keep sending IRQs and amos to it until the heartbeat times out.
- */
- (void)xp_nofault_PIOR((u64 *)GLOBAL_MMR_ADDR(NASID_GET(&amo->
- variable),
- xp_nofault_PIOR_target));
-
- local_irq_restore(irq_flags);
-}
-
-static int
-xpc_partition_deactivation_requested_sn2(short partid)
-{
- struct amo *amo = xpc_vars_sn2->amos_page +
- XPC_DEACTIVATE_REQUEST_AMO_SN2;
-
- /* our partition's amo variable ANDed with partid mask */
- return (FETCHOP_LOAD_OP(TO_AMO((u64)&amo->variable), FETCHOP_LOAD) &
- BIT(partid)) != 0;
-}
-
-/*
- * Update the remote partition's info.
- */
-static void
-xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version,
- unsigned long *remote_rp_ts_jiffies,
- unsigned long remote_rp_pa,
- unsigned long remote_vars_pa,
- struct xpc_vars_sn2 *remote_vars)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
-
- part->remote_rp_version = remote_rp_version;
- dev_dbg(xpc_part, " remote_rp_version = 0x%016x\n",
- part->remote_rp_version);
-
- part->remote_rp_ts_jiffies = *remote_rp_ts_jiffies;
- dev_dbg(xpc_part, " remote_rp_ts_jiffies = 0x%016lx\n",
- part->remote_rp_ts_jiffies);
-
- part->remote_rp_pa = remote_rp_pa;
- dev_dbg(xpc_part, " remote_rp_pa = 0x%016lx\n", part->remote_rp_pa);
-
- part_sn2->remote_vars_pa = remote_vars_pa;
- dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n",
- part_sn2->remote_vars_pa);
-
- part->last_heartbeat = remote_vars->heartbeat - 1;
- dev_dbg(xpc_part, " last_heartbeat = 0x%016llx\n",
- part->last_heartbeat);
-
- part_sn2->remote_vars_part_pa = remote_vars->vars_part_pa;
- dev_dbg(xpc_part, " remote_vars_part_pa = 0x%016lx\n",
- part_sn2->remote_vars_part_pa);
-
- part_sn2->activate_IRQ_nasid = remote_vars->activate_IRQ_nasid;
- dev_dbg(xpc_part, " activate_IRQ_nasid = 0x%x\n",
- part_sn2->activate_IRQ_nasid);
-
- part_sn2->activate_IRQ_phys_cpuid =
- remote_vars->activate_IRQ_phys_cpuid;
- dev_dbg(xpc_part, " activate_IRQ_phys_cpuid = 0x%x\n",
- part_sn2->activate_IRQ_phys_cpuid);
-
- part_sn2->remote_amos_page_pa = remote_vars->amos_page_pa;
- dev_dbg(xpc_part, " remote_amos_page_pa = 0x%lx\n",
- part_sn2->remote_amos_page_pa);
-
- part_sn2->remote_vars_version = remote_vars->version;
- dev_dbg(xpc_part, " remote_vars_version = 0x%x\n",
- part_sn2->remote_vars_version);
-}
-
-/*
- * Prior code has determined the nasid which generated a activate IRQ.
- * Inspect that nasid to determine if its partition needs to be activated
- * or deactivated.
- *
- * A partition is considered "awaiting activation" if our partition
- * flags indicate it is not active and it has a heartbeat. A
- * partition is considered "awaiting deactivation" if our partition
- * flags indicate it is active but it has no heartbeat or it is not
- * sending its heartbeat to us.
- *
- * To determine the heartbeat, the remote nasid must have a properly
- * initialized reserved page.
- */
-static void
-xpc_identify_activate_IRQ_req_sn2(int nasid)
-{
- struct xpc_rsvd_page *remote_rp;
- struct xpc_vars_sn2 *remote_vars;
- unsigned long remote_rp_pa;
- unsigned long remote_vars_pa;
- int remote_rp_version;
- int reactivate = 0;
- unsigned long remote_rp_ts_jiffies = 0;
- short partid;
- struct xpc_partition *part;
- struct xpc_partition_sn2 *part_sn2;
- enum xp_retval ret;
-
- /* pull over the reserved page structure */
-
- remote_rp = (struct xpc_rsvd_page *)xpc_remote_copy_buffer_sn2;
-
- ret = xpc_get_remote_rp(nasid, NULL, remote_rp, &remote_rp_pa);
- if (ret != xpSuccess) {
- dev_warn(xpc_part, "unable to get reserved page from nasid %d, "
- "which sent interrupt, reason=%d\n", nasid, ret);
- return;
- }
-
- remote_vars_pa = remote_rp->sn.sn2.vars_pa;
- remote_rp_version = remote_rp->version;
- remote_rp_ts_jiffies = remote_rp->ts_jiffies;
-
- partid = remote_rp->SAL_partid;
- part = &xpc_partitions[partid];
- part_sn2 = &part->sn.sn2;
-
- /* pull over the cross partition variables */
-
- remote_vars = (struct xpc_vars_sn2 *)xpc_remote_copy_buffer_sn2;
-
- ret = xpc_get_remote_vars_sn2(remote_vars_pa, remote_vars);
- if (ret != xpSuccess) {
- dev_warn(xpc_part, "unable to get XPC variables from nasid %d, "
- "which sent interrupt, reason=%d\n", nasid, ret);
-
- XPC_DEACTIVATE_PARTITION(part, ret);
- return;
- }
-
- part->activate_IRQ_rcvd++;
-
- dev_dbg(xpc_part, "partid for nasid %d is %d; IRQs = %d; HB = "
- "%lld:0x%lx\n", (int)nasid, (int)partid,
- part->activate_IRQ_rcvd,
- remote_vars->heartbeat, remote_vars->heartbeating_to_mask[0]);
-
- if (xpc_partition_disengaged(part) &&
- part->act_state == XPC_P_AS_INACTIVE) {
-
- xpc_update_partition_info_sn2(part, remote_rp_version,
- &remote_rp_ts_jiffies,
- remote_rp_pa, remote_vars_pa,
- remote_vars);
-
- if (xpc_partition_deactivation_requested_sn2(partid)) {
- /*
- * Other side is waiting on us to deactivate even though
- * we already have.
- */
- return;
- }
-
- xpc_activate_partition(part);
- return;
- }
-
- DBUG_ON(part->remote_rp_version == 0);
- DBUG_ON(part_sn2->remote_vars_version == 0);
-
- if (remote_rp_ts_jiffies != part->remote_rp_ts_jiffies) {
-
- /* the other side rebooted */
-
- DBUG_ON(xpc_partition_engaged_sn2(partid));
- DBUG_ON(xpc_partition_deactivation_requested_sn2(partid));
-
- xpc_update_partition_info_sn2(part, remote_rp_version,
- &remote_rp_ts_jiffies,
- remote_rp_pa, remote_vars_pa,
- remote_vars);
- reactivate = 1;
- }
-
- if (part->disengage_timeout > 0 && !xpc_partition_disengaged(part)) {
- /* still waiting on other side to disengage from us */
- return;
- }
-
- if (reactivate)
- XPC_DEACTIVATE_PARTITION(part, xpReactivating);
- else if (xpc_partition_deactivation_requested_sn2(partid))
- XPC_DEACTIVATE_PARTITION(part, xpOtherGoingDown);
-}
-
-/*
- * Loop through the activation amo variables and process any bits
- * which are set. Each bit indicates a nasid sending a partition
- * activation or deactivation request.
- *
- * Return #of IRQs detected.
- */
-int
-xpc_identify_activate_IRQ_sender_sn2(void)
-{
- int l;
- int b;
- unsigned long nasid_mask_long;
- u64 nasid; /* remote nasid */
- int n_IRQs_detected = 0;
- struct amo *act_amos;
-
- act_amos = xpc_vars_sn2->amos_page + XPC_ACTIVATE_IRQ_AMOS_SN2;
-
- /* scan through activate amo variables looking for non-zero entries */
- for (l = 0; l < xpc_nasid_mask_nlongs; l++) {
-
- if (xpc_exiting)
- break;
-
- nasid_mask_long = xpc_receive_IRQ_amo_sn2(&act_amos[l]);
-
- b = find_first_bit(&nasid_mask_long, BITS_PER_LONG);
- if (b >= BITS_PER_LONG) {
- /* no IRQs from nasids in this amo variable */
- continue;
- }
-
- dev_dbg(xpc_part, "amo[%d] gave back 0x%lx\n", l,
- nasid_mask_long);
-
- /*
- * If this nasid has been added to the machine since
- * our partition was reset, this will retain the
- * remote nasid in our reserved pages machine mask.
- * This is used in the event of module reload.
- */
- xpc_mach_nasids[l] |= nasid_mask_long;
-
- /* locate the nasid(s) which sent interrupts */
-
- do {
- n_IRQs_detected++;
- nasid = (l * BITS_PER_LONG + b) * 2;
- dev_dbg(xpc_part, "interrupt from nasid %lld\n", nasid);
- xpc_identify_activate_IRQ_req_sn2(nasid);
-
- b = find_next_bit(&nasid_mask_long, BITS_PER_LONG,
- b + 1);
- } while (b < BITS_PER_LONG);
- }
- return n_IRQs_detected;
-}
-
-static void
-xpc_process_activate_IRQ_rcvd_sn2(void)
-{
- unsigned long irq_flags;
- int n_IRQs_expected;
- int n_IRQs_detected;
-
- spin_lock_irqsave(&xpc_activate_IRQ_rcvd_lock, irq_flags);
- n_IRQs_expected = xpc_activate_IRQ_rcvd;
- xpc_activate_IRQ_rcvd = 0;
- spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags);
-
- n_IRQs_detected = xpc_identify_activate_IRQ_sender_sn2();
- if (n_IRQs_detected < n_IRQs_expected) {
- /* retry once to help avoid missing amo */
- (void)xpc_identify_activate_IRQ_sender_sn2();
- }
-}
-
-/*
- * Setup the channel structures that are sn2 specific.
- */
-static enum xp_retval
-xpc_setup_ch_structures_sn2(struct xpc_partition *part)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- struct xpc_channel_sn2 *ch_sn2;
- enum xp_retval retval;
- int ret;
- int cpuid;
- int ch_number;
- struct timer_list *timer;
- short partid = XPC_PARTID(part);
-
- /* allocate all the required GET/PUT values */
-
- part_sn2->local_GPs =
- xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL,
- &part_sn2->local_GPs_base);
- if (part_sn2->local_GPs == NULL) {
- dev_err(xpc_chan, "can't get memory for local get/put "
- "values\n");
- return xpNoMemory;
- }
-
- part_sn2->remote_GPs =
- xpc_kzalloc_cacheline_aligned(XPC_GP_SIZE, GFP_KERNEL,
- &part_sn2->remote_GPs_base);
- if (part_sn2->remote_GPs == NULL) {
- dev_err(xpc_chan, "can't get memory for remote get/put "
- "values\n");
- retval = xpNoMemory;
- goto out_1;
- }
-
- part_sn2->remote_GPs_pa = 0;
-
- /* allocate all the required open and close args */
-
- part_sn2->local_openclose_args =
- xpc_kzalloc_cacheline_aligned(XPC_OPENCLOSE_ARGS_SIZE,
- GFP_KERNEL, &part_sn2->
- local_openclose_args_base);
- if (part_sn2->local_openclose_args == NULL) {
- dev_err(xpc_chan, "can't get memory for local connect args\n");
- retval = xpNoMemory;
- goto out_2;
- }
-
- part_sn2->remote_openclose_args_pa = 0;
-
- part_sn2->local_chctl_amo_va = xpc_init_IRQ_amo_sn2(partid);
-
- part_sn2->notify_IRQ_nasid = 0;
- part_sn2->notify_IRQ_phys_cpuid = 0;
- part_sn2->remote_chctl_amo_va = NULL;
-
- sprintf(part_sn2->notify_IRQ_owner, "xpc%02d", partid);
- ret = request_irq(SGI_XPC_NOTIFY, xpc_handle_notify_IRQ_sn2,
- IRQF_SHARED, part_sn2->notify_IRQ_owner,
- (void *)(u64)partid);
- if (ret != 0) {
- dev_err(xpc_chan, "can't register NOTIFY IRQ handler, "
- "errno=%d\n", -ret);
- retval = xpLackOfResources;
- goto out_3;
- }
-
- /* Setup a timer to check for dropped notify IRQs */
- timer = &part_sn2->dropped_notify_IRQ_timer;
- timer_setup(timer, xpc_check_for_dropped_notify_IRQ_sn2, 0);
- timer->expires = jiffies + XPC_DROPPED_NOTIFY_IRQ_WAIT_INTERVAL;
- add_timer(timer);
-
- for (ch_number = 0; ch_number < part->nchannels; ch_number++) {
- ch_sn2 = &part->channels[ch_number].sn.sn2;
-
- ch_sn2->local_GP = &part_sn2->local_GPs[ch_number];
- ch_sn2->local_openclose_args =
- &part_sn2->local_openclose_args[ch_number];
-
- mutex_init(&ch_sn2->msg_to_pull_mutex);
- }
-
- /*
- * Setup the per partition specific variables required by the
- * remote partition to establish channel connections with us.
- *
- * The setting of the magic # indicates that these per partition
- * specific variables are ready to be used.
- */
- xpc_vars_part_sn2[partid].GPs_pa = xp_pa(part_sn2->local_GPs);
- xpc_vars_part_sn2[partid].openclose_args_pa =
- xp_pa(part_sn2->local_openclose_args);
- xpc_vars_part_sn2[partid].chctl_amo_pa =
- xp_pa(part_sn2->local_chctl_amo_va);
- cpuid = raw_smp_processor_id(); /* any CPU in this partition will do */
- xpc_vars_part_sn2[partid].notify_IRQ_nasid = cpuid_to_nasid(cpuid);
- xpc_vars_part_sn2[partid].notify_IRQ_phys_cpuid =
- cpu_physical_id(cpuid);
- xpc_vars_part_sn2[partid].nchannels = part->nchannels;
- xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC1_SN2;
-
- return xpSuccess;
-
- /* setup of ch structures failed */
-out_3:
- kfree(part_sn2->local_openclose_args_base);
- part_sn2->local_openclose_args = NULL;
-out_2:
- kfree(part_sn2->remote_GPs_base);
- part_sn2->remote_GPs = NULL;
-out_1:
- kfree(part_sn2->local_GPs_base);
- part_sn2->local_GPs = NULL;
- return retval;
-}
-
-/*
- * Teardown the channel structures that are sn2 specific.
- */
-static void
-xpc_teardown_ch_structures_sn2(struct xpc_partition *part)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- short partid = XPC_PARTID(part);
-
- /*
- * Indicate that the variables specific to the remote partition are no
- * longer available for its use.
- */
- xpc_vars_part_sn2[partid].magic = 0;
-
- /* in case we've still got outstanding timers registered... */
- del_timer_sync(&part_sn2->dropped_notify_IRQ_timer);
- free_irq(SGI_XPC_NOTIFY, (void *)(u64)partid);
-
- kfree(part_sn2->local_openclose_args_base);
- part_sn2->local_openclose_args = NULL;
- kfree(part_sn2->remote_GPs_base);
- part_sn2->remote_GPs = NULL;
- kfree(part_sn2->local_GPs_base);
- part_sn2->local_GPs = NULL;
- part_sn2->local_chctl_amo_va = NULL;
-}
-
-/*
- * Create a wrapper that hides the underlying mechanism for pulling a cacheline
- * (or multiple cachelines) from a remote partition.
- *
- * src_pa must be a cacheline aligned physical address on the remote partition.
- * dst must be a cacheline aligned virtual address on this partition.
- * cnt must be cacheline sized
- */
-/* ??? Replace this function by call to xp_remote_memcpy() or bte_copy()? */
-static enum xp_retval
-xpc_pull_remote_cachelines_sn2(struct xpc_partition *part, void *dst,
- const unsigned long src_pa, size_t cnt)
-{
- enum xp_retval ret;
-
- DBUG_ON(src_pa != L1_CACHE_ALIGN(src_pa));
- DBUG_ON((unsigned long)dst != L1_CACHE_ALIGN((unsigned long)dst));
- DBUG_ON(cnt != L1_CACHE_ALIGN(cnt));
-
- if (part->act_state == XPC_P_AS_DEACTIVATING)
- return part->reason;
-
- ret = xp_remote_memcpy(xp_pa(dst), src_pa, cnt);
- if (ret != xpSuccess) {
- dev_dbg(xpc_chan, "xp_remote_memcpy() from partition %d failed,"
- " ret=%d\n", XPC_PARTID(part), ret);
- }
- return ret;
-}
-
-/*
- * Pull the remote per partition specific variables from the specified
- * partition.
- */
-static enum xp_retval
-xpc_pull_remote_vars_part_sn2(struct xpc_partition *part)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- u8 buffer[L1_CACHE_BYTES * 2];
- struct xpc_vars_part_sn2 *pulled_entry_cacheline =
- (struct xpc_vars_part_sn2 *)L1_CACHE_ALIGN((u64)buffer);
- struct xpc_vars_part_sn2 *pulled_entry;
- unsigned long remote_entry_cacheline_pa;
- unsigned long remote_entry_pa;
- short partid = XPC_PARTID(part);
- enum xp_retval ret;
-
- /* pull the cacheline that contains the variables we're interested in */
-
- DBUG_ON(part_sn2->remote_vars_part_pa !=
- L1_CACHE_ALIGN(part_sn2->remote_vars_part_pa));
- DBUG_ON(sizeof(struct xpc_vars_part_sn2) != L1_CACHE_BYTES / 2);
-
- remote_entry_pa = part_sn2->remote_vars_part_pa +
- sn_partition_id * sizeof(struct xpc_vars_part_sn2);
-
- remote_entry_cacheline_pa = (remote_entry_pa & ~(L1_CACHE_BYTES - 1));
-
- pulled_entry = (struct xpc_vars_part_sn2 *)((u64)pulled_entry_cacheline
- + (remote_entry_pa &
- (L1_CACHE_BYTES - 1)));
-
- ret = xpc_pull_remote_cachelines_sn2(part, pulled_entry_cacheline,
- remote_entry_cacheline_pa,
- L1_CACHE_BYTES);
- if (ret != xpSuccess) {
- dev_dbg(xpc_chan, "failed to pull XPC vars_part from "
- "partition %d, ret=%d\n", partid, ret);
- return ret;
- }
-
- /* see if they've been set up yet */
-
- if (pulled_entry->magic != XPC_VP_MAGIC1_SN2 &&
- pulled_entry->magic != XPC_VP_MAGIC2_SN2) {
-
- if (pulled_entry->magic != 0) {
- dev_dbg(xpc_chan, "partition %d's XPC vars_part for "
- "partition %d has bad magic value (=0x%llx)\n",
- partid, sn_partition_id, pulled_entry->magic);
- return xpBadMagic;
- }
-
- /* they've not been initialized yet */
- return xpRetry;
- }
-
- if (xpc_vars_part_sn2[partid].magic == XPC_VP_MAGIC1_SN2) {
-
- /* validate the variables */
-
- if (pulled_entry->GPs_pa == 0 ||
- pulled_entry->openclose_args_pa == 0 ||
- pulled_entry->chctl_amo_pa == 0) {
-
- dev_err(xpc_chan, "partition %d's XPC vars_part for "
- "partition %d are not valid\n", partid,
- sn_partition_id);
- return xpInvalidAddress;
- }
-
- /* the variables we imported look to be valid */
-
- part_sn2->remote_GPs_pa = pulled_entry->GPs_pa;
- part_sn2->remote_openclose_args_pa =
- pulled_entry->openclose_args_pa;
- part_sn2->remote_chctl_amo_va =
- (struct amo *)__va(pulled_entry->chctl_amo_pa);
- part_sn2->notify_IRQ_nasid = pulled_entry->notify_IRQ_nasid;
- part_sn2->notify_IRQ_phys_cpuid =
- pulled_entry->notify_IRQ_phys_cpuid;
-
- if (part->nchannels > pulled_entry->nchannels)
- part->nchannels = pulled_entry->nchannels;
-
- /* let the other side know that we've pulled their variables */
-
- xpc_vars_part_sn2[partid].magic = XPC_VP_MAGIC2_SN2;
- }
-
- if (pulled_entry->magic == XPC_VP_MAGIC1_SN2)
- return xpRetry;
-
- return xpSuccess;
-}
-
-/*
- * Establish first contact with the remote partititon. This involves pulling
- * the XPC per partition variables from the remote partition and waiting for
- * the remote partition to pull ours.
- */
-static enum xp_retval
-xpc_make_first_contact_sn2(struct xpc_partition *part)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- enum xp_retval ret;
-
- /*
- * Register the remote partition's amos with SAL so it can handle
- * and cleanup errors within that address range should the remote
- * partition go down. We don't unregister this range because it is
- * difficult to tell when outstanding writes to the remote partition
- * are finished and thus when it is safe to unregister. This should
- * not result in wasted space in the SAL xp_addr_region table because
- * we should get the same page for remote_amos_page_pa after module
- * reloads and system reboots.
- */
- if (sn_register_xp_addr_region(part_sn2->remote_amos_page_pa,
- PAGE_SIZE, 1) < 0) {
- dev_warn(xpc_part, "xpc_activating(%d) failed to register "
- "xp_addr region\n", XPC_PARTID(part));
-
- ret = xpPhysAddrRegFailed;
- XPC_DEACTIVATE_PARTITION(part, ret);
- return ret;
- }
-
- /*
- * Send activate IRQ to get other side to activate if they've not
- * already begun to do so.
- */
- xpc_send_activate_IRQ_sn2(part_sn2->remote_amos_page_pa,
- cnodeid_to_nasid(0),
- part_sn2->activate_IRQ_nasid,
- part_sn2->activate_IRQ_phys_cpuid);
-
- while ((ret = xpc_pull_remote_vars_part_sn2(part)) != xpSuccess) {
- if (ret != xpRetry) {
- XPC_DEACTIVATE_PARTITION(part, ret);
- return ret;
- }
-
- dev_dbg(xpc_part, "waiting to make first contact with "
- "partition %d\n", XPC_PARTID(part));
-
- /* wait a 1/4 of a second or so */
- (void)msleep_interruptible(250);
-
- if (part->act_state == XPC_P_AS_DEACTIVATING)
- return part->reason;
- }
-
- return xpSuccess;
-}
-
-/*
- * Get the chctl flags and pull the openclose args and/or remote GPs as needed.
- */
-static u64
-xpc_get_chctl_all_flags_sn2(struct xpc_partition *part)
-{
- struct xpc_partition_sn2 *part_sn2 = &part->sn.sn2;
- unsigned long irq_flags;
- union xpc_channel_ctl_flags chctl;
- enum xp_retval ret;
-
- /*
- * See if there are any chctl flags to be handled.
- */
-
- spin_lock_irqsave(&part->chctl_lock, irq_flags);
- chctl = part->chctl;
- if (chctl.all_flags != 0)
- part->chctl.all_flags = 0;
-
- spin_unlock_irqrestore(&part->chctl_lock, irq_flags);
-
- if (xpc_any_openclose_chctl_flags_set(&chctl)) {
- ret = xpc_pull_remote_cachelines_sn2(part, part->
- remote_openclose_args,
- part_sn2->
- remote_openclose_args_pa,
- XPC_OPENCLOSE_ARGS_SIZE);
- if (ret != xpSuccess) {
- XPC_DEACTIVATE_PARTITION(part, ret);
-
- dev_dbg(xpc_chan, "failed to pull openclose args from "
- "partition %d, ret=%d\n", XPC_PARTID(part),
- ret);
-
- /* don't bother processing chctl flags anymore */
- chctl.all_flags = 0;
- }
- }
-
- if (xpc_any_msg_chctl_flags_set(&chctl)) {
- ret = xpc_pull_remote_cachelines_sn2(part, part_sn2->remote_GPs,
- part_sn2->remote_GPs_pa,
- XPC_GP_SIZE);
- if (ret != xpSuccess) {
- XPC_DEACTIVATE_PARTITION(part, ret);
-
- dev_dbg(xpc_chan, "failed to pull GPs from partition "
- "%d, ret=%d\n", XPC_PARTID(part), ret);
-
- /* don't bother processing chctl flags anymore */
- chctl.all_flags = 0;
- }
- }
-
- return chctl.all_flags;
-}
-
-/*
- * Allocate the local message queue and the notify queue.
- */
-static enum xp_retval
-xpc_allocate_local_msgqueue_sn2(struct xpc_channel *ch)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- unsigned long irq_flags;
- int nentries;
- size_t nbytes;
-
- for (nentries = ch->local_nentries; nentries > 0; nentries--) {
-
- nbytes = nentries * ch->entry_size;
- ch_sn2->local_msgqueue =
- xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL,
- &ch_sn2->local_msgqueue_base);
- if (ch_sn2->local_msgqueue == NULL)
- continue;
-
- nbytes = nentries * sizeof(struct xpc_notify_sn2);
- ch_sn2->notify_queue = kzalloc(nbytes, GFP_KERNEL);
- if (ch_sn2->notify_queue == NULL) {
- kfree(ch_sn2->local_msgqueue_base);
- ch_sn2->local_msgqueue = NULL;
- continue;
- }
-
- spin_lock_irqsave(&ch->lock, irq_flags);
- if (nentries < ch->local_nentries) {
- dev_dbg(xpc_chan, "nentries=%d local_nentries=%d, "
- "partid=%d, channel=%d\n", nentries,
- ch->local_nentries, ch->partid, ch->number);
-
- ch->local_nentries = nentries;
- }
- spin_unlock_irqrestore(&ch->lock, irq_flags);
- return xpSuccess;
- }
-
- dev_dbg(xpc_chan, "can't get memory for local message queue and notify "
- "queue, partid=%d, channel=%d\n", ch->partid, ch->number);
- return xpNoMemory;
-}
-
-/*
- * Allocate the cached remote message queue.
- */
-static enum xp_retval
-xpc_allocate_remote_msgqueue_sn2(struct xpc_channel *ch)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- unsigned long irq_flags;
- int nentries;
- size_t nbytes;
-
- DBUG_ON(ch->remote_nentries <= 0);
-
- for (nentries = ch->remote_nentries; nentries > 0; nentries--) {
-
- nbytes = nentries * ch->entry_size;
- ch_sn2->remote_msgqueue =
- xpc_kzalloc_cacheline_aligned(nbytes, GFP_KERNEL, &ch_sn2->
- remote_msgqueue_base);
- if (ch_sn2->remote_msgqueue == NULL)
- continue;
-
- spin_lock_irqsave(&ch->lock, irq_flags);
- if (nentries < ch->remote_nentries) {
- dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, "
- "partid=%d, channel=%d\n", nentries,
- ch->remote_nentries, ch->partid, ch->number);
-
- ch->remote_nentries = nentries;
- }
- spin_unlock_irqrestore(&ch->lock, irq_flags);
- return xpSuccess;
- }
-
- dev_dbg(xpc_chan, "can't get memory for cached remote message queue, "
- "partid=%d, channel=%d\n", ch->partid, ch->number);
- return xpNoMemory;
-}
-
-/*
- * Allocate message queues and other stuff associated with a channel.
- *
- * Note: Assumes all of the channel sizes are filled in.
- */
-static enum xp_retval
-xpc_setup_msg_structures_sn2(struct xpc_channel *ch)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- enum xp_retval ret;
-
- DBUG_ON(ch->flags & XPC_C_SETUP);
-
- ret = xpc_allocate_local_msgqueue_sn2(ch);
- if (ret == xpSuccess) {
-
- ret = xpc_allocate_remote_msgqueue_sn2(ch);
- if (ret != xpSuccess) {
- kfree(ch_sn2->local_msgqueue_base);
- ch_sn2->local_msgqueue = NULL;
- kfree(ch_sn2->notify_queue);
- ch_sn2->notify_queue = NULL;
- }
- }
- return ret;
-}
-
-/*
- * Free up message queues and other stuff that were allocated for the specified
- * channel.
- */
-static void
-xpc_teardown_msg_structures_sn2(struct xpc_channel *ch)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
-
- lockdep_assert_held(&ch->lock);
-
- ch_sn2->remote_msgqueue_pa = 0;
-
- ch_sn2->local_GP->get = 0;
- ch_sn2->local_GP->put = 0;
- ch_sn2->remote_GP.get = 0;
- ch_sn2->remote_GP.put = 0;
- ch_sn2->w_local_GP.get = 0;
- ch_sn2->w_local_GP.put = 0;
- ch_sn2->w_remote_GP.get = 0;
- ch_sn2->w_remote_GP.put = 0;
- ch_sn2->next_msg_to_pull = 0;
-
- if (ch->flags & XPC_C_SETUP) {
- dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n",
- ch->flags, ch->partid, ch->number);
-
- kfree(ch_sn2->local_msgqueue_base);
- ch_sn2->local_msgqueue = NULL;
- kfree(ch_sn2->remote_msgqueue_base);
- ch_sn2->remote_msgqueue = NULL;
- kfree(ch_sn2->notify_queue);
- ch_sn2->notify_queue = NULL;
- }
-}
-
-/*
- * Notify those who wanted to be notified upon delivery of their message.
- */
-static void
-xpc_notify_senders_sn2(struct xpc_channel *ch, enum xp_retval reason, s64 put)
-{
- struct xpc_notify_sn2 *notify;
- u8 notify_type;
- s64 get = ch->sn.sn2.w_remote_GP.get - 1;
-
- while (++get < put && atomic_read(&ch->n_to_notify) > 0) {
-
- notify = &ch->sn.sn2.notify_queue[get % ch->local_nentries];
-
- /*
- * See if the notify entry indicates it was associated with
- * a message who's sender wants to be notified. It is possible
- * that it is, but someone else is doing or has done the
- * notification.
- */
- notify_type = notify->type;
- if (notify_type == 0 ||
- cmpxchg(&notify->type, notify_type, 0) != notify_type) {
- continue;
- }
-
- DBUG_ON(notify_type != XPC_N_CALL);
-
- atomic_dec(&ch->n_to_notify);
-
- if (notify->func != NULL) {
- dev_dbg(xpc_chan, "notify->func() called, notify=0x%p "
- "msg_number=%lld partid=%d channel=%d\n",
- (void *)notify, get, ch->partid, ch->number);
-
- notify->func(reason, ch->partid, ch->number,
- notify->key);
-
- dev_dbg(xpc_chan, "notify->func() returned, notify=0x%p"
- " msg_number=%lld partid=%d channel=%d\n",
- (void *)notify, get, ch->partid, ch->number);
- }
- }
-}
-
-static void
-xpc_notify_senders_of_disconnect_sn2(struct xpc_channel *ch)
-{
- xpc_notify_senders_sn2(ch, ch->reason, ch->sn.sn2.w_local_GP.put);
-}
-
-/*
- * Clear some of the msg flags in the local message queue.
- */
-static inline void
-xpc_clear_local_msgqueue_flags_sn2(struct xpc_channel *ch)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg_sn2 *msg;
- s64 get;
-
- get = ch_sn2->w_remote_GP.get;
- do {
- msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue +
- (get % ch->local_nentries) *
- ch->entry_size);
- DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
- msg->flags = 0;
- } while (++get < ch_sn2->remote_GP.get);
-}
-
-/*
- * Clear some of the msg flags in the remote message queue.
- */
-static inline void
-xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg_sn2 *msg;
- s64 put, remote_nentries = ch->remote_nentries;
-
- /* flags are zeroed when the buffer is allocated */
- if (ch_sn2->remote_GP.put < remote_nentries)
- return;
-
- put = max(ch_sn2->w_remote_GP.put, remote_nentries);
- do {
- msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
- (put % remote_nentries) *
- ch->entry_size);
- DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
- DBUG_ON(!(msg->flags & XPC_M_SN2_DONE));
- DBUG_ON(msg->number != put - remote_nentries);
- msg->flags = 0;
- } while (++put < ch_sn2->remote_GP.put);
-}
-
-static int
-xpc_n_of_deliverable_payloads_sn2(struct xpc_channel *ch)
-{
- return ch->sn.sn2.w_remote_GP.put - ch->sn.sn2.w_local_GP.get;
-}
-
-static void
-xpc_process_msg_chctl_flags_sn2(struct xpc_partition *part, int ch_number)
-{
- struct xpc_channel *ch = &part->channels[ch_number];
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- int npayloads_sent;
-
- ch_sn2->remote_GP = part->sn.sn2.remote_GPs[ch_number];
-
- /* See what, if anything, has changed for each connected channel */
-
- xpc_msgqueue_ref(ch);
-
- if (ch_sn2->w_remote_GP.get == ch_sn2->remote_GP.get &&
- ch_sn2->w_remote_GP.put == ch_sn2->remote_GP.put) {
- /* nothing changed since GPs were last pulled */
- xpc_msgqueue_deref(ch);
- return;
- }
-
- if (!(ch->flags & XPC_C_CONNECTED)) {
- xpc_msgqueue_deref(ch);
- return;
- }
-
- /*
- * First check to see if messages recently sent by us have been
- * received by the other side. (The remote GET value will have
- * changed since we last looked at it.)
- */
-
- if (ch_sn2->w_remote_GP.get != ch_sn2->remote_GP.get) {
-
- /*
- * We need to notify any senders that want to be notified
- * that their sent messages have been received by their
- * intended recipients. We need to do this before updating
- * w_remote_GP.get so that we don't allocate the same message
- * queue entries prematurely (see xpc_allocate_msg()).
- */
- if (atomic_read(&ch->n_to_notify) > 0) {
- /*
- * Notify senders that messages sent have been
- * received and delivered by the other side.
- */
- xpc_notify_senders_sn2(ch, xpMsgDelivered,
- ch_sn2->remote_GP.get);
- }
-
- /*
- * Clear msg->flags in previously sent messages, so that
- * they're ready for xpc_allocate_msg().
- */
- xpc_clear_local_msgqueue_flags_sn2(ch);
-
- ch_sn2->w_remote_GP.get = ch_sn2->remote_GP.get;
-
- dev_dbg(xpc_chan, "w_remote_GP.get changed to %lld, partid=%d, "
- "channel=%d\n", ch_sn2->w_remote_GP.get, ch->partid,
- ch->number);
-
- /*
- * If anyone was waiting for message queue entries to become
- * available, wake them up.
- */
- if (atomic_read(&ch->n_on_msg_allocate_wq) > 0)
- wake_up(&ch->msg_allocate_wq);
- }
-
- /*
- * Now check for newly sent messages by the other side. (The remote
- * PUT value will have changed since we last looked at it.)
- */
-
- if (ch_sn2->w_remote_GP.put != ch_sn2->remote_GP.put) {
- /*
- * Clear msg->flags in previously received messages, so that
- * they're ready for xpc_get_deliverable_payload_sn2().
- */
- xpc_clear_remote_msgqueue_flags_sn2(ch);
-
- smp_wmb(); /* ensure flags have been cleared before bte_copy */
- ch_sn2->w_remote_GP.put = ch_sn2->remote_GP.put;
-
- dev_dbg(xpc_chan, "w_remote_GP.put changed to %lld, partid=%d, "
- "channel=%d\n", ch_sn2->w_remote_GP.put, ch->partid,
- ch->number);
-
- npayloads_sent = xpc_n_of_deliverable_payloads_sn2(ch);
- if (npayloads_sent > 0) {
- dev_dbg(xpc_chan, "msgs waiting to be copied and "
- "delivered=%d, partid=%d, channel=%d\n",
- npayloads_sent, ch->partid, ch->number);
-
- if (ch->flags & XPC_C_CONNECTEDCALLOUT_MADE)
- xpc_activate_kthreads(ch, npayloads_sent);
- }
- }
-
- xpc_msgqueue_deref(ch);
-}
-
-static struct xpc_msg_sn2 *
-xpc_pull_remote_msg_sn2(struct xpc_channel *ch, s64 get)
-{
- struct xpc_partition *part = &xpc_partitions[ch->partid];
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- unsigned long remote_msg_pa;
- struct xpc_msg_sn2 *msg;
- u32 msg_index;
- u32 nmsgs;
- u64 msg_offset;
- enum xp_retval ret;
-
- if (mutex_lock_interruptible(&ch_sn2->msg_to_pull_mutex) != 0) {
- /* we were interrupted by a signal */
- return NULL;
- }
-
- while (get >= ch_sn2->next_msg_to_pull) {
-
- /* pull as many messages as are ready and able to be pulled */
-
- msg_index = ch_sn2->next_msg_to_pull % ch->remote_nentries;
-
- DBUG_ON(ch_sn2->next_msg_to_pull >= ch_sn2->w_remote_GP.put);
- nmsgs = ch_sn2->w_remote_GP.put - ch_sn2->next_msg_to_pull;
- if (msg_index + nmsgs > ch->remote_nentries) {
- /* ignore the ones that wrap the msg queue for now */
- nmsgs = ch->remote_nentries - msg_index;
- }
-
- msg_offset = msg_index * ch->entry_size;
- msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue +
- msg_offset);
- remote_msg_pa = ch_sn2->remote_msgqueue_pa + msg_offset;
-
- ret = xpc_pull_remote_cachelines_sn2(part, msg, remote_msg_pa,
- nmsgs * ch->entry_size);
- if (ret != xpSuccess) {
-
- dev_dbg(xpc_chan, "failed to pull %d msgs starting with"
- " msg %lld from partition %d, channel=%d, "
- "ret=%d\n", nmsgs, ch_sn2->next_msg_to_pull,
- ch->partid, ch->number, ret);
-
- XPC_DEACTIVATE_PARTITION(part, ret);
-
- mutex_unlock(&ch_sn2->msg_to_pull_mutex);
- return NULL;
- }
-
- ch_sn2->next_msg_to_pull += nmsgs;
- }
-
- mutex_unlock(&ch_sn2->msg_to_pull_mutex);
-
- /* return the message we were looking for */
- msg_offset = (get % ch->remote_nentries) * ch->entry_size;
- msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + msg_offset);
-
- return msg;
-}
-
-/*
- * Get the next deliverable message's payload.
- */
-static void *
-xpc_get_deliverable_payload_sn2(struct xpc_channel *ch)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg_sn2 *msg;
- void *payload = NULL;
- s64 get;
-
- do {
- if (ch->flags & XPC_C_DISCONNECTING)
- break;
-
- get = ch_sn2->w_local_GP.get;
- smp_rmb(); /* guarantee that .get loads before .put */
- if (get == ch_sn2->w_remote_GP.put)
- break;
-
- /* There are messages waiting to be pulled and delivered.
- * We need to try to secure one for ourselves. We'll do this
- * by trying to increment w_local_GP.get and hope that no one
- * else beats us to it. If they do, we'll we'll simply have
- * to try again for the next one.
- */
-
- if (cmpxchg(&ch_sn2->w_local_GP.get, get, get + 1) == get) {
- /* we got the entry referenced by get */
-
- dev_dbg(xpc_chan, "w_local_GP.get changed to %lld, "
- "partid=%d, channel=%d\n", get + 1,
- ch->partid, ch->number);
-
- /* pull the message from the remote partition */
-
- msg = xpc_pull_remote_msg_sn2(ch, get);
-
- if (msg != NULL) {
- DBUG_ON(msg->number != get);
- DBUG_ON(msg->flags & XPC_M_SN2_DONE);
- DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
-
- payload = &msg->payload;
- }
- break;
- }
-
- } while (1);
-
- return payload;
-}
-
-/*
- * Now we actually send the messages that are ready to be sent by advancing
- * the local message queue's Put value and then send a chctl msgrequest to the
- * recipient partition.
- */
-static void
-xpc_send_msgs_sn2(struct xpc_channel *ch, s64 initial_put)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg_sn2 *msg;
- s64 put = initial_put + 1;
- int send_msgrequest = 0;
-
- while (1) {
-
- while (1) {
- if (put == ch_sn2->w_local_GP.put)
- break;
-
- msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->
- local_msgqueue + (put %
- ch->local_nentries) *
- ch->entry_size);
-
- if (!(msg->flags & XPC_M_SN2_READY))
- break;
-
- put++;
- }
-
- if (put == initial_put) {
- /* nothing's changed */
- break;
- }
-
- if (cmpxchg_rel(&ch_sn2->local_GP->put, initial_put, put) !=
- initial_put) {
- /* someone else beat us to it */
- DBUG_ON(ch_sn2->local_GP->put < initial_put);
- break;
- }
-
- /* we just set the new value of local_GP->put */
-
- dev_dbg(xpc_chan, "local_GP->put changed to %lld, partid=%d, "
- "channel=%d\n", put, ch->partid, ch->number);
-
- send_msgrequest = 1;
-
- /*
- * We need to ensure that the message referenced by
- * local_GP->put is not XPC_M_SN2_READY or that local_GP->put
- * equals w_local_GP.put, so we'll go have a look.
- */
- initial_put = put;
- }
-
- if (send_msgrequest)
- xpc_send_chctl_msgrequest_sn2(ch);
-}
-
-/*
- * Allocate an entry for a message from the message queue associated with the
- * specified channel.
- */
-static enum xp_retval
-xpc_allocate_msg_sn2(struct xpc_channel *ch, u32 flags,
- struct xpc_msg_sn2 **address_of_msg)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg_sn2 *msg;
- enum xp_retval ret;
- s64 put;
-
- /*
- * Get the next available message entry from the local message queue.
- * If none are available, we'll make sure that we grab the latest
- * GP values.
- */
- ret = xpTimeout;
-
- while (1) {
-
- put = ch_sn2->w_local_GP.put;
- smp_rmb(); /* guarantee that .put loads before .get */
- if (put - ch_sn2->w_remote_GP.get < ch->local_nentries) {
-
- /* There are available message entries. We need to try
- * to secure one for ourselves. We'll do this by trying
- * to increment w_local_GP.put as long as someone else
- * doesn't beat us to it. If they do, we'll have to
- * try again.
- */
- if (cmpxchg(&ch_sn2->w_local_GP.put, put, put + 1) ==
- put) {
- /* we got the entry referenced by put */
- break;
- }
- continue; /* try again */
- }
-
- /*
- * There aren't any available msg entries at this time.
- *
- * In waiting for a message entry to become available,
- * we set a timeout in case the other side is not sending
- * completion interrupts. This lets us fake a notify IRQ
- * that will cause the notify IRQ handler to fetch the latest
- * GP values as if an interrupt was sent by the other side.
- */
- if (ret == xpTimeout)
- xpc_send_chctl_local_msgrequest_sn2(ch);
-
- if (flags & XPC_NOWAIT)
- return xpNoWait;
-
- ret = xpc_allocate_msg_wait(ch);
- if (ret != xpInterrupted && ret != xpTimeout)
- return ret;
- }
-
- /* get the message's address and initialize it */
- msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->local_msgqueue +
- (put % ch->local_nentries) *
- ch->entry_size);
-
- DBUG_ON(msg->flags != 0);
- msg->number = put;
-
- dev_dbg(xpc_chan, "w_local_GP.put changed to %lld; msg=0x%p, "
- "msg_number=%lld, partid=%d, channel=%d\n", put + 1,
- (void *)msg, msg->number, ch->partid, ch->number);
-
- *address_of_msg = msg;
- return xpSuccess;
-}
-
-/*
- * Common code that does the actual sending of the message by advancing the
- * local message queue's Put value and sends a chctl msgrequest to the
- * partition the message is being sent to.
- */
-static enum xp_retval
-xpc_send_payload_sn2(struct xpc_channel *ch, u32 flags, void *payload,
- u16 payload_size, u8 notify_type, xpc_notify_func func,
- void *key)
-{
- enum xp_retval ret = xpSuccess;
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg_sn2 *msg = msg;
- struct xpc_notify_sn2 *notify = notify;
- s64 msg_number;
- s64 put;
-
- DBUG_ON(notify_type == XPC_N_CALL && func == NULL);
-
- if (XPC_MSG_SIZE(payload_size) > ch->entry_size)
- return xpPayloadTooBig;
-
- xpc_msgqueue_ref(ch);
-
- if (ch->flags & XPC_C_DISCONNECTING) {
- ret = ch->reason;
- goto out_1;
- }
- if (!(ch->flags & XPC_C_CONNECTED)) {
- ret = xpNotConnected;
- goto out_1;
- }
-
- ret = xpc_allocate_msg_sn2(ch, flags, &msg);
- if (ret != xpSuccess)
- goto out_1;
-
- msg_number = msg->number;
-
- if (notify_type != 0) {
- /*
- * Tell the remote side to send an ACK interrupt when the
- * message has been delivered.
- */
- msg->flags |= XPC_M_SN2_INTERRUPT;
-
- atomic_inc(&ch->n_to_notify);
-
- notify = &ch_sn2->notify_queue[msg_number % ch->local_nentries];
- notify->func = func;
- notify->key = key;
- notify->type = notify_type;
-
- /* ??? Is a mb() needed here? */
-
- if (ch->flags & XPC_C_DISCONNECTING) {
- /*
- * An error occurred between our last error check and
- * this one. We will try to clear the type field from
- * the notify entry. If we succeed then
- * xpc_disconnect_channel() didn't already process
- * the notify entry.
- */
- if (cmpxchg(&notify->type, notify_type, 0) ==
- notify_type) {
- atomic_dec(&ch->n_to_notify);
- ret = ch->reason;
- }
- goto out_1;
- }
- }
-
- memcpy(&msg->payload, payload, payload_size);
-
- msg->flags |= XPC_M_SN2_READY;
-
- /*
- * The preceding store of msg->flags must occur before the following
- * load of local_GP->put.
- */
- smp_mb();
-
- /* see if the message is next in line to be sent, if so send it */
-
- put = ch_sn2->local_GP->put;
- if (put == msg_number)
- xpc_send_msgs_sn2(ch, put);
-
-out_1:
- xpc_msgqueue_deref(ch);
- return ret;
-}
-
-/*
- * Now we actually acknowledge the messages that have been delivered and ack'd
- * by advancing the cached remote message queue's Get value and if requested
- * send a chctl msgrequest to the message sender's partition.
- *
- * If a message has XPC_M_SN2_INTERRUPT set, send an interrupt to the partition
- * that sent the message.
- */
-static void
-xpc_acknowledge_msgs_sn2(struct xpc_channel *ch, s64 initial_get, u8 msg_flags)
-{
- struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2;
- struct xpc_msg_sn2 *msg;
- s64 get = initial_get + 1;
- int send_msgrequest = 0;
-
- while (1) {
-
- while (1) {
- if (get == ch_sn2->w_local_GP.get)
- break;
-
- msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->
- remote_msgqueue + (get %
- ch->remote_nentries) *
- ch->entry_size);
-
- if (!(msg->flags & XPC_M_SN2_DONE))
- break;
-
- msg_flags |= msg->flags;
- get++;
- }
-
- if (get == initial_get) {
- /* nothing's changed */
- break;
- }
-
- if (cmpxchg_rel(&ch_sn2->local_GP->get, initial_get, get) !=
- initial_get) {
- /* someone else beat us to it */
- DBUG_ON(ch_sn2->local_GP->get <= initial_get);
- break;
- }
-
- /* we just set the new value of local_GP->get */
-
- dev_dbg(xpc_chan, "local_GP->get changed to %lld, partid=%d, "
- "channel=%d\n", get, ch->partid, ch->number);
-
- send_msgrequest = (msg_flags & XPC_M_SN2_INTERRUPT);
-
- /*
- * We need to ensure that the message referenced by
- * local_GP->get is not XPC_M_SN2_DONE or that local_GP->get
- * equals w_local_GP.get, so we'll go have a look.
- */
- initial_get = get;
- }
-
- if (send_msgrequest)
- xpc_send_chctl_msgrequest_sn2(ch);
-}
-
-static void
-xpc_received_payload_sn2(struct xpc_channel *ch, void *payload)
-{
- struct xpc_msg_sn2 *msg;
- s64 msg_number;
- s64 get;
-
- msg = container_of(payload, struct xpc_msg_sn2, payload);
- msg_number = msg->number;
-
- dev_dbg(xpc_chan, "msg=0x%p, msg_number=%lld, partid=%d, channel=%d\n",
- (void *)msg, msg_number, ch->partid, ch->number);
-
- DBUG_ON((((u64)msg - (u64)ch->sn.sn2.remote_msgqueue) / ch->entry_size) !=
- msg_number % ch->remote_nentries);
- DBUG_ON(!(msg->flags & XPC_M_SN2_READY));
- DBUG_ON(msg->flags & XPC_M_SN2_DONE);
-
- msg->flags |= XPC_M_SN2_DONE;
-
- /*
- * The preceding store of msg->flags must occur before the following
- * load of local_GP->get.
- */
- smp_mb();
-
- /*
- * See if this message is next in line to be acknowledged as having
- * been delivered.
- */
- get = ch->sn.sn2.local_GP->get;
- if (get == msg_number)
- xpc_acknowledge_msgs_sn2(ch, get, msg->flags);
-}
-
-static struct xpc_arch_operations xpc_arch_ops_sn2 = {
- .setup_partitions = xpc_setup_partitions_sn2,
- .teardown_partitions = xpc_teardown_partitions_sn2,
- .process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_sn2,
- .get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2,
- .setup_rsvd_page = xpc_setup_rsvd_page_sn2,
-
- .allow_hb = xpc_allow_hb_sn2,
- .disallow_hb = xpc_disallow_hb_sn2,
- .disallow_all_hbs = xpc_disallow_all_hbs_sn2,
- .increment_heartbeat = xpc_increment_heartbeat_sn2,
- .offline_heartbeat = xpc_offline_heartbeat_sn2,
- .online_heartbeat = xpc_online_heartbeat_sn2,
- .heartbeat_init = xpc_heartbeat_init_sn2,
- .heartbeat_exit = xpc_heartbeat_exit_sn2,
- .get_remote_heartbeat = xpc_get_remote_heartbeat_sn2,
-
- .request_partition_activation =
- xpc_request_partition_activation_sn2,
- .request_partition_reactivation =
- xpc_request_partition_reactivation_sn2,
- .request_partition_deactivation =
- xpc_request_partition_deactivation_sn2,
- .cancel_partition_deactivation_request =
- xpc_cancel_partition_deactivation_request_sn2,
-
- .setup_ch_structures = xpc_setup_ch_structures_sn2,
- .teardown_ch_structures = xpc_teardown_ch_structures_sn2,
-
- .make_first_contact = xpc_make_first_contact_sn2,
-
- .get_chctl_all_flags = xpc_get_chctl_all_flags_sn2,
- .send_chctl_closerequest = xpc_send_chctl_closerequest_sn2,
- .send_chctl_closereply = xpc_send_chctl_closereply_sn2,
- .send_chctl_openrequest = xpc_send_chctl_openrequest_sn2,
- .send_chctl_openreply = xpc_send_chctl_openreply_sn2,
- .send_chctl_opencomplete = xpc_send_chctl_opencomplete_sn2,
- .process_msg_chctl_flags = xpc_process_msg_chctl_flags_sn2,
-
- .save_remote_msgqueue_pa = xpc_save_remote_msgqueue_pa_sn2,
-
- .setup_msg_structures = xpc_setup_msg_structures_sn2,
- .teardown_msg_structures = xpc_teardown_msg_structures_sn2,
-
- .indicate_partition_engaged = xpc_indicate_partition_engaged_sn2,
- .indicate_partition_disengaged = xpc_indicate_partition_disengaged_sn2,
- .partition_engaged = xpc_partition_engaged_sn2,
- .any_partition_engaged = xpc_any_partition_engaged_sn2,
- .assume_partition_disengaged = xpc_assume_partition_disengaged_sn2,
-
- .n_of_deliverable_payloads = xpc_n_of_deliverable_payloads_sn2,
- .send_payload = xpc_send_payload_sn2,
- .get_deliverable_payload = xpc_get_deliverable_payload_sn2,
- .received_payload = xpc_received_payload_sn2,
- .notify_senders_of_disconnect = xpc_notify_senders_of_disconnect_sn2,
-};
-
-int
-xpc_init_sn2(void)
-{
- int ret;
- size_t buf_size;
-
- xpc_arch_ops = xpc_arch_ops_sn2;
-
- if (offsetof(struct xpc_msg_sn2, payload) > XPC_MSG_HDR_MAX_SIZE) {
- dev_err(xpc_part, "header portion of struct xpc_msg_sn2 is "
- "larger than %d\n", XPC_MSG_HDR_MAX_SIZE);
- return -E2BIG;
- }
-
- buf_size = max(XPC_RP_VARS_SIZE,
- XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES_SN2);
- xpc_remote_copy_buffer_sn2 = xpc_kmalloc_cacheline_aligned(buf_size,
- GFP_KERNEL,
- &xpc_remote_copy_buffer_base_sn2);
- if (xpc_remote_copy_buffer_sn2 == NULL) {
- dev_err(xpc_part, "can't get memory for remote copy buffer\n");
- return -ENOMEM;
- }
-
- /* open up protections for IPI and [potentially] amo operations */
- xpc_allow_IPI_ops_sn2();
- xpc_allow_amo_ops_shub_wars_1_1_sn2();
-
- /*
- * This is safe to do before the xpc_hb_checker thread has started
- * because the handler releases a wait queue. If an interrupt is
- * received before the thread is waiting, it will not go to sleep,
- * but rather immediately process the interrupt.
- */
- ret = request_irq(SGI_XPC_ACTIVATE, xpc_handle_activate_IRQ_sn2, 0,
- "xpc hb", NULL);
- if (ret != 0) {
- dev_err(xpc_part, "can't register ACTIVATE IRQ handler, "
- "errno=%d\n", -ret);
- xpc_disallow_IPI_ops_sn2();
- kfree(xpc_remote_copy_buffer_base_sn2);
- }
- return ret;
-}
-
-void
-xpc_exit_sn2(void)
-{
- free_irq(SGI_XPC_ACTIVATE, NULL);
- xpc_disallow_IPI_ops_sn2();
- kfree(xpc_remote_copy_buffer_base_sn2);
-}
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 0c6de97dd347..09e24659ef3d 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -27,7 +27,7 @@
#if defined CONFIG_X86_64
#include <asm/uv/bios.h>
#include <asm/uv/uv_irq.h>
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
#include <asm/sn/intr.h>
#include <asm/sn/sn_sal.h>
#endif
@@ -35,7 +35,7 @@
#include "../sgi-gru/grukservices.h"
#include "xpc.h"
-#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#if defined CONFIG_IA64_SGI_UV
struct uv_IO_APIC_route_entry {
__u64 vector : 8,
delivery_mode : 3,
@@ -48,6 +48,8 @@ struct uv_IO_APIC_route_entry {
__reserved_2 : 15,
dest : 32;
};
+
+#define sn_partition_id 0
#endif
static struct xpc_heartbeat_uv *xpc_heartbeat_uv;
@@ -119,7 +121,7 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset);
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0)
mq->irq = SGI_XPC_ACTIVATE;
else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0)
@@ -142,7 +144,7 @@ xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
#if defined CONFIG_X86_64
uv_teardown_irq(mq->irq);
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
int mmr_pnode;
unsigned long mmr_value;
@@ -160,7 +162,7 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq)
{
int ret;
-#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#if defined CONFIG_IA64_SGI_UV
int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
ret = sn_mq_watchlist_alloc(mmr_pnode, (void *)uv_gpa(mq->address),
@@ -195,7 +197,7 @@ xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq)
#if defined CONFIG_X86_64
ret = uv_bios_mq_watchlist_free(mmr_pnode, mq->watchlist_num);
BUG_ON(ret != BIOS_STATUS_SUCCESS);
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
ret = sn_mq_watchlist_free(mmr_pnode, mq->watchlist_num);
BUG_ON(ret != SALRET_OK);
#else
@@ -794,7 +796,7 @@ xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa,
else
ret = xpBiosError;
-#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
+#elif defined CONFIG_IA64_SGI_UV
status = sn_partition_reserved_page_pa((u64)buf, cookie, rp_pa, len);
if (status == SALRET_OK)
ret = xpSuccess;
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index 44d750d98bc8..f7d610a22347 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -515,7 +515,7 @@ xpnet_init(void)
{
int result;
- if (!is_shub() && !is_uv())
+ if (!is_uv())
return -ENODEV;
dev_info(xpnet, "registering network device %s\n", XPNET_DEVICE_NAME);
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index e9f78eb390d2..e7b493c22bf3 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -147,15 +147,6 @@ config HOTPLUG_PCI_RPA_DLPAR
When in doubt, say N.
-config HOTPLUG_PCI_SGI
- tristate "SGI PCI Hotplug Support"
- depends on IA64_SGI_SN2 || IA64_GENERIC
- help
- Say Y here if you want to use the SGI Altix Hotplug
- Driver for PCI devices.
-
- When in doubt, say N.
-
config HOTPLUG_PCI_S390
bool "System z PCI Hotplug Support"
depends on S390 && 64BIT
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 7e3331603714..5196983220df 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -18,7 +18,6 @@ obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o
obj-$(CONFIG_HOTPLUG_PCI_POWERNV) += pnv-php.o
obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o
obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o
-obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
deleted file mode 100644
index 231f5bdd3d2d..000000000000
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ /dev/null
@@ -1,700 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2005-2006 Silicon Graphics, Inc. All rights reserved.
- *
- * This work was based on the 2.4/2.6 kernel development by Dick Reigner.
- * Work to add BIOS PROM support was completed by Mike Habeck.
- */
-
-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci_hotplug.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/mutex.h>
-
-#include <asm/sn/addrs.h>
-#include <asm/sn/geo.h>
-#include <asm/sn/l1.h>
-#include <asm/sn/module.h>
-#include <asm/sn/pcibr_provider.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include <asm/sn/sn_feature_sets.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/types.h>
-#include <asm/sn/acpi.h>
-
-#include "../pci.h"
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
-MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
-
-
-/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
-#define PCI_SLOT_ALREADY_UP 2 /* slot already up */
-#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */
-#define PCI_L1_ERR 7 /* L1 console command error */
-#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */
-
-
-#define PCIIO_ASIC_TYPE_TIOCA 4
-#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
-#define SN_MAX_HP_SLOTS 32 /* max hotplug slots */
-#define SN_SLOT_NAME_SIZE 33 /* size of name string */
-
-/* internal list head */
-static struct list_head sn_hp_list;
-
-/* hotplug_slot struct's private pointer */
-struct slot {
- int device_num;
- struct pci_bus *pci_bus;
- /* this struct for glue internal only */
- struct hotplug_slot hotplug_slot;
- struct list_head hp_list;
- char physical_path[SN_SLOT_NAME_SIZE];
-};
-
-struct pcibr_slot_enable_resp {
- int resp_sub_errno;
- char resp_l1_msg[PCI_L1_QSIZE + 1];
-};
-
-struct pcibr_slot_disable_resp {
- int resp_sub_errno;
- char resp_l1_msg[PCI_L1_QSIZE + 1];
-};
-
-enum sn_pci_req_e {
- PCI_REQ_SLOT_ELIGIBLE,
- PCI_REQ_SLOT_DISABLE
-};
-
-static int enable_slot(struct hotplug_slot *slot);
-static int disable_slot(struct hotplug_slot *slot);
-static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
-
-static const struct hotplug_slot_ops sn_hotplug_slot_ops = {
- .enable_slot = enable_slot,
- .disable_slot = disable_slot,
- .get_power_status = get_power_status,
-};
-
-static DEFINE_MUTEX(sn_hotplug_mutex);
-
-static struct slot *to_slot(struct hotplug_slot *bss_hotplug_slot)
-{
- return container_of(bss_hotplug_slot, struct slot, hotplug_slot);
-}
-
-static ssize_t path_show(struct pci_slot *pci_slot, char *buf)
-{
- int retval = -ENOENT;
- struct slot *slot = to_slot(pci_slot->hotplug);
-
- if (!slot)
- return retval;
-
- retval = sprintf(buf, "%s\n", slot->physical_path);
- return retval;
-}
-
-static struct pci_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
-
-static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
-{
- struct pcibus_info *pcibus_info;
- u16 busnum, segment, ioboard_type;
-
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
-
- /* Check to see if this is a valid slot on 'pci_bus' */
- if (!(pcibus_info->pbi_valid_devices & (1 << device)))
- return -EPERM;
-
- ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
- busnum = pcibus_info->pbi_buscommon.bs_persist_busnum;
- segment = pci_domain_nr(pci_bus) & 0xf;
-
- /* Do not allow hotplug operations on base I/O cards */
- if ((ioboard_type == L1_BRICKTYPE_IX ||
- ioboard_type == L1_BRICKTYPE_IA) &&
- (segment == 1 && busnum == 0 && device != 1))
- return -EPERM;
-
- return 1;
-}
-
-static int sn_pci_bus_valid(struct pci_bus *pci_bus)
-{
- struct pcibus_info *pcibus_info;
- u32 asic_type;
- u16 ioboard_type;
-
- /* Don't register slots hanging off the TIOCA bus */
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
- asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
- if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
- return -EPERM;
-
- /* Only register slots in I/O Bricks that support hotplug */
- ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
- switch (ioboard_type) {
- case L1_BRICKTYPE_IX:
- case L1_BRICKTYPE_PX:
- case L1_BRICKTYPE_IA:
- case L1_BRICKTYPE_PA:
- case L1_BOARDTYPE_PCIX3SLOT:
- return 1;
- break;
- default:
- return -EPERM;
- break;
- }
-
- return -EIO;
-}
-
-static int sn_hp_slot_private_alloc(struct hotplug_slot **bss_hotplug_slot,
- struct pci_bus *pci_bus, int device,
- char *name)
-{
- struct pcibus_info *pcibus_info;
- struct slot *slot;
-
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
-
- slot = kzalloc(sizeof(*slot), GFP_KERNEL);
- if (!slot)
- return -ENOMEM;
-
- slot->device_num = device;
- slot->pci_bus = pci_bus;
- sprintf(name, "%04x:%02x:%02x",
- pci_domain_nr(pci_bus),
- ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
- device + 1);
-
- sn_generate_path(pci_bus, slot->physical_path);
-
- list_add(&slot->hp_list, &sn_hp_list);
- *bss_hotplug_slot = &slot->hotplug_slot;
-
- return 0;
-}
-
-static struct hotplug_slot *sn_hp_destroy(void)
-{
- struct slot *slot;
- struct pci_slot *pci_slot;
- struct hotplug_slot *bss_hotplug_slot = NULL;
-
- list_for_each_entry(slot, &sn_hp_list, hp_list) {
- bss_hotplug_slot = &slot->hotplug_slot;
- pci_slot = bss_hotplug_slot->pci_slot;
- list_del(&slot->hp_list);
- sysfs_remove_file(&pci_slot->kobj,
- &sn_slot_path_attr.attr);
- break;
- }
- return bss_hotplug_slot;
-}
-
-static void sn_bus_free_data(struct pci_dev *dev)
-{
- struct pci_bus *subordinate_bus;
- struct pci_dev *child;
-
- /* Recursively clean up sn_irq_info structs */
- if (dev->subordinate) {
- subordinate_bus = dev->subordinate;
- list_for_each_entry(child, &subordinate_bus->devices, bus_list)
- sn_bus_free_data(child);
- }
- /*
- * Some drivers may use dma accesses during the
- * driver remove function. We release the sysdata
- * areas after the driver remove functions have
- * been called.
- */
- sn_bus_store_sysdata(dev);
- sn_pci_unfixup_slot(dev);
-}
-
-static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
- int device_num, char **ssdt)
-{
- struct slot *slot = to_slot(bss_hotplug_slot);
- struct pcibus_info *pcibus_info;
- struct pcibr_slot_enable_resp resp;
- int rc;
-
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-
- /*
- * Power-on and initialize the slot in the SN
- * PCI infrastructure.
- */
- rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
-
-
- if (rc == PCI_SLOT_ALREADY_UP) {
- pci_dbg(slot->pci_bus->self, "is already active\n");
- return 1; /* return 1 to user */
- }
-
- if (rc == PCI_L1_ERR) {
- pci_dbg(slot->pci_bus->self, "L1 failure %d with message: %s",
- resp.resp_sub_errno, resp.resp_l1_msg);
- return -EPERM;
- }
-
- if (rc) {
- pci_dbg(slot->pci_bus->self, "insert failed with error %d sub-error %d\n",
- rc, resp.resp_sub_errno);
- return -EIO;
- }
-
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
- pcibus_info->pbi_enabled_devices |= (1 << device_num);
-
- return 0;
-}
-
-static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
- int device_num, int action)
-{
- struct slot *slot = to_slot(bss_hotplug_slot);
- struct pcibus_info *pcibus_info;
- struct pcibr_slot_disable_resp resp;
- int rc;
-
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
-
- rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp);
-
- if ((action == PCI_REQ_SLOT_ELIGIBLE) &&
- (rc == PCI_SLOT_ALREADY_DOWN)) {
- pci_dbg(slot->pci_bus->self, "Slot %s already inactive\n", slot->physical_path);
- return 1; /* return 1 to user */
- }
-
- if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_EMPTY_33MHZ)) {
- pci_dbg(slot->pci_bus->self, "Cannot remove last 33MHz card\n");
- return -EPERM;
- }
-
- if ((action == PCI_REQ_SLOT_ELIGIBLE) && (rc == PCI_L1_ERR)) {
- pci_dbg(slot->pci_bus->self, "L1 failure %d with message \n%s\n",
- resp.resp_sub_errno, resp.resp_l1_msg);
- return -EPERM;
- }
-
- if ((action == PCI_REQ_SLOT_ELIGIBLE) && rc) {
- pci_dbg(slot->pci_bus->self, "remove failed with error %d sub-error %d\n",
- rc, resp.resp_sub_errno);
- return -EIO;
- }
-
- if ((action == PCI_REQ_SLOT_ELIGIBLE) && !rc)
- return 0;
-
- if ((action == PCI_REQ_SLOT_DISABLE) && !rc) {
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
- pcibus_info->pbi_enabled_devices &= ~(1 << device_num);
- pci_dbg(slot->pci_bus->self, "remove successful\n");
- return 0;
- }
-
- if ((action == PCI_REQ_SLOT_DISABLE) && rc) {
- pci_dbg(slot->pci_bus->self, "remove failed rc = %d\n", rc);
- }
-
- return rc;
-}
-
-/*
- * Power up and configure the slot via a SAL call to PROM.
- * Scan slot (and any children), do any platform specific fixup,
- * and find device driver.
- */
-static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
-{
- struct slot *slot = to_slot(bss_hotplug_slot);
- struct pci_bus *new_bus = NULL;
- struct pci_dev *dev;
- int num_funcs;
- int new_ppb = 0;
- int rc;
- char *ssdt = NULL;
- void pcibios_fixup_device_resources(struct pci_dev *);
-
- /* Serialize the Linux PCI infrastructure */
- mutex_lock(&sn_hotplug_mutex);
-
- /*
- * Power-on and initialize the slot in the SN
- * PCI infrastructure. Also, retrieve the ACPI SSDT
- * table for the slot (if ACPI capable PROM).
- */
- rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
- if (rc) {
- mutex_unlock(&sn_hotplug_mutex);
- return rc;
- }
-
- if (ssdt)
- ssdt = __va(ssdt);
- /* Add the new SSDT for the slot to the ACPI namespace */
- if (SN_ACPI_BASE_SUPPORT() && ssdt) {
- acpi_status ret;
-
- ret = acpi_load_table((struct acpi_table_header *)ssdt);
- if (ACPI_FAILURE(ret)) {
- printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
- __func__, ret);
- /* try to continue on */
- }
- }
-
- num_funcs = pci_scan_slot(slot->pci_bus,
- PCI_DEVFN(slot->device_num + 1, 0));
- if (!num_funcs) {
- pci_dbg(slot->pci_bus->self, "no device in slot\n");
- mutex_unlock(&sn_hotplug_mutex);
- return -ENODEV;
- }
-
- /*
- * Map SN resources for all functions on the card
- * to the Linux PCI interface and tell the drivers
- * about them.
- */
- list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) {
- if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
- continue;
-
- /* Need to do slot fixup on PPB before fixup of children
- * (PPB's pcidev_info needs to be in pcidev_info list
- * before child's SN_PCIDEV_INFO() call to setup
- * pdi_host_pcidev_info).
- */
- pcibios_fixup_device_resources(dev);
- if (SN_ACPI_BASE_SUPPORT())
- sn_acpi_slot_fixup(dev);
- else
- sn_io_slot_fixup(dev);
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- pci_hp_add_bridge(dev);
- if (dev->subordinate) {
- new_bus = dev->subordinate;
- new_ppb = 1;
- }
- }
- }
-
- /*
- * Add the slot's devices to the ACPI infrastructure */
- if (SN_ACPI_BASE_SUPPORT() && ssdt) {
- unsigned long long adr;
- struct acpi_device *pdevice;
- acpi_handle phandle;
- acpi_handle chandle = NULL;
- acpi_handle rethandle;
- acpi_status ret;
-
- phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion);
-
- if (acpi_bus_get_device(phandle, &pdevice)) {
- pci_dbg(slot->pci_bus->self, "no parent device, assuming NULL\n");
- pdevice = NULL;
- }
-
- acpi_scan_lock_acquire();
- /*
- * Walk the rootbus node's immediate children looking for
- * the slot's device node(s). There can be more than
- * one for multifunction devices.
- */
- for (;;) {
- rethandle = NULL;
- ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
- phandle, chandle,
- &rethandle);
-
- if (ret == AE_NOT_FOUND || rethandle == NULL)
- break;
-
- chandle = rethandle;
-
- ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
- NULL, &adr);
-
- if (ACPI_SUCCESS(ret) &&
- (adr>>16) == (slot->device_num + 1)) {
-
- ret = acpi_bus_scan(chandle);
- if (ACPI_FAILURE(ret)) {
- printk(KERN_ERR "%s: acpi_bus_scan failed (0x%x) for slot %d func %d\n",
- __func__, ret, (int)(adr>>16),
- (int)(adr&0xffff));
- /* try to continue on */
- }
- }
- }
- acpi_scan_lock_release();
- }
-
- pci_lock_rescan_remove();
-
- /* Call the driver for the new device */
- pci_bus_add_devices(slot->pci_bus);
- /* Call the drivers for the new devices subordinate to PPB */
- if (new_ppb)
- pci_bus_add_devices(new_bus);
-
- pci_unlock_rescan_remove();
- mutex_unlock(&sn_hotplug_mutex);
-
- if (rc == 0)
- pci_dbg(slot->pci_bus->self, "insert operation successful\n");
- else
- pci_dbg(slot->pci_bus->self, "insert operation failed rc = %d\n", rc);
-
- return rc;
-}
-
-static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
-{
- struct slot *slot = to_slot(bss_hotplug_slot);
- struct pci_dev *dev, *temp;
- int rc;
- acpi_handle ssdt_hdl = NULL;
-
- /* Acquire update access to the bus */
- mutex_lock(&sn_hotplug_mutex);
-
- /* is it okay to bring this slot down? */
- rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
- PCI_REQ_SLOT_ELIGIBLE);
- if (rc)
- goto leaving;
-
- /* free the ACPI resources for the slot */
- if (SN_ACPI_BASE_SUPPORT() &&
- PCI_CONTROLLER(slot->pci_bus)->companion) {
- unsigned long long adr;
- struct acpi_device *device;
- acpi_handle phandle;
- acpi_handle chandle = NULL;
- acpi_handle rethandle;
- acpi_status ret;
-
- /* Get the rootbus node pointer */
- phandle = acpi_device_handle(PCI_CONTROLLER(slot->pci_bus)->companion);
-
- acpi_scan_lock_acquire();
- /*
- * Walk the rootbus node's immediate children looking for
- * the slot's device node(s). There can be more than
- * one for multifunction devices.
- */
- for (;;) {
- rethandle = NULL;
- ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
- phandle, chandle,
- &rethandle);
-
- if (ret == AE_NOT_FOUND || rethandle == NULL)
- break;
-
- chandle = rethandle;
-
- ret = acpi_evaluate_integer(chandle,
- METHOD_NAME__ADR,
- NULL, &adr);
- if (ACPI_SUCCESS(ret) &&
- (adr>>16) == (slot->device_num + 1)) {
- /* retain the owner id */
- ssdt_hdl = chandle;
-
- ret = acpi_bus_get_device(chandle,
- &device);
- if (ACPI_SUCCESS(ret))
- acpi_bus_trim(device);
- }
- }
- acpi_scan_lock_release();
- }
-
- pci_lock_rescan_remove();
- /* Free the SN resources assigned to the Linux device.*/
- list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
- if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
- continue;
-
- pci_dev_get(dev);
- sn_bus_free_data(dev);
- pci_stop_and_remove_bus_device(dev);
- pci_dev_put(dev);
- }
- pci_unlock_rescan_remove();
-
- /* Remove the SSDT for the slot from the ACPI namespace */
- if (SN_ACPI_BASE_SUPPORT() && ssdt_hdl) {
- acpi_status ret;
- ret = acpi_unload_parent_table(ssdt_hdl);
- if (ACPI_FAILURE(ret)) {
- acpi_handle_err(ssdt_hdl,
- "%s: acpi_unload_parent_table failed (0x%x)\n",
- __func__, ret);
- /* try to continue on */
- }
- }
-
- /* free the collected sysdata pointers */
- sn_bus_free_sysdata();
-
- /* Deactivate slot */
- rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
- PCI_REQ_SLOT_DISABLE);
- leaving:
- /* Release the bus lock */
- mutex_unlock(&sn_hotplug_mutex);
-
- return rc;
-}
-
-static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
- u8 *value)
-{
- struct slot *slot = to_slot(bss_hotplug_slot);
- struct pcibus_info *pcibus_info;
- u32 power;
-
- pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
- mutex_lock(&sn_hotplug_mutex);
- power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
- *value = power ? 1 : 0;
- mutex_unlock(&sn_hotplug_mutex);
- return 0;
-}
-
-static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
-{
- kfree(to_slot(bss_hotplug_slot));
-}
-
-static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
-{
- int device;
- struct pci_slot *pci_slot;
- struct hotplug_slot *bss_hotplug_slot;
- char name[SN_SLOT_NAME_SIZE];
- int rc = 0;
-
- /*
- * Currently only four devices are supported,
- * in the future there maybe more -- up to 32.
- */
-
- for (device = 0; device < SN_MAX_HP_SLOTS ; device++) {
- if (sn_pci_slot_valid(pci_bus, device) != 1)
- continue;
-
- if (sn_hp_slot_private_alloc(&bss_hotplug_slot,
- pci_bus, device, name)) {
- rc = -ENOMEM;
- goto alloc_err;
- }
- bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
-
- rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name);
- if (rc)
- goto register_err;
-
- pci_slot = bss_hotplug_slot->pci_slot;
- rc = sysfs_create_file(&pci_slot->kobj,
- &sn_slot_path_attr.attr);
- if (rc)
- goto alloc_err;
- }
- pci_dbg(pci_bus->self, "Registered bus with hotplug\n");
- return rc;
-
-register_err:
- pci_dbg(pci_bus->self, "bus failed to register with err = %d\n",
- rc);
-
- /* destroy THIS element */
- sn_hp_destroy();
- sn_release_slot(bss_hotplug_slot);
-
-alloc_err:
- /* destroy anything else on the list */
- while ((bss_hotplug_slot = sn_hp_destroy())) {
- pci_hp_deregister(bss_hotplug_slot);
- sn_release_slot(bss_hotplug_slot);
- }
-
- return rc;
-}
-
-static int __init sn_pci_hotplug_init(void)
-{
- struct pci_bus *pci_bus = NULL;
- int rc;
- int registered = 0;
-
- if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) {
- printk(KERN_ERR "%s: PROM version does not support hotplug.\n",
- __func__);
- return -EPERM;
- }
-
- INIT_LIST_HEAD(&sn_hp_list);
-
- while ((pci_bus = pci_find_next_bus(pci_bus))) {
- if (!pci_bus->sysdata)
- continue;
-
- rc = sn_pci_bus_valid(pci_bus);
- if (rc != 1) {
- pci_dbg(pci_bus->self, "not a valid hotplug bus\n");
- continue;
- }
- pci_dbg(pci_bus->self, "valid hotplug bus\n");
-
- rc = sn_hotplug_slot_register(pci_bus);
- if (!rc) {
- registered = 1;
- } else {
- registered = 0;
- break;
- }
- }
-
- return registered == 1 ? 0 : -ENODEV;
-}
-
-static void __exit sn_pci_hotplug_exit(void)
-{
- struct hotplug_slot *bss_hotplug_slot;
-
- while ((bss_hotplug_slot = sn_hp_destroy())) {
- pci_hp_deregister(bss_hotplug_slot);
- sn_release_slot(bss_hotplug_slot);
- }
-
- if (!list_empty(&sn_hp_list))
- printk(KERN_ERR "%s: internal list is not empty\n", __FILE__);
-}
-
-module_init(sn_pci_hotplug_init);
-module_exit(sn_pci_hotplug_exit);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index e5760c4a27f0..832af4213046 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -357,10 +357,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
-#include <asm/sn/io.h>
-#endif
-
/*
* Compile time Options:
@@ -380,11 +376,6 @@
#define NVRAM_DELAY() udelay(500) /* 2 microseconds */
-#if defined(__ia64__) && !defined(ia64_platform_is)
-#define ia64_platform_is(foo) (!strcmp(x, platform_name))
-#endif
-
-
#define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020)
#define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \
ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240)
@@ -1427,15 +1418,6 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha)
ha->flags.reset_active = 0;
ha->flags.abort_isp_active = 0;
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
- if (ia64_platform_is("sn2")) {
- printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
- "dual channel lockup workaround\n", ha->host_no);
- ha->flags.use_pci_vchannel = 1;
- driver_setup.no_nvram = 1;
- }
-#endif
-
/* TODO: implement support for the 1040 nvram format */
if (IS_ISP1040(ha))
driver_setup.no_nvram = 1;
@@ -2251,13 +2233,6 @@ qla1280_nvram_config(struct scsi_qla_host *ha)
mb[1] = nv->firmware_feature.f.enable_fast_posting;
mb[1] |= nv->firmware_feature.f.report_lvd_bus_transition << 1;
mb[1] |= nv->firmware_feature.f.disable_synchronous_backoff << 5;
-#if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2)
- if (ia64_platform_is("sn2")) {
- printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
- "workaround\n", ha->host_no);
- mb[1] |= nv->firmware_feature.f.unused_9 << 9; /* XXX */
- }
-#endif
status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
/* Retry count and delay. */
@@ -2888,12 +2863,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
break;
dma_handle = sg_dma_address(s);
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
- if (ha->flags.use_pci_vchannel)
- sn_pci_set_vchan(ha->pdev,
- (unsigned long *)&dma_handle,
- SCSI_BUS_32(cmd));
-#endif
*dword_ptr++ =
cpu_to_le32(lower_32_bits(dma_handle));
*dword_ptr++ =
@@ -2950,12 +2919,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
if (cnt == 5)
break;
dma_handle = sg_dma_address(s);
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
- if (ha->flags.use_pci_vchannel)
- sn_pci_set_vchan(ha->pdev,
- (unsigned long *)&dma_handle,
- SCSI_BUS_32(cmd));
-#endif
*dword_ptr++ =
cpu_to_le32(lower_32_bits(dma_handle));
*dword_ptr++ =
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
index b496206362a9..a1a8aefc7cc3 100644
--- a/drivers/scsi/qla1280.h
+++ b/drivers/scsi/qla1280.h
@@ -1055,9 +1055,6 @@ struct scsi_qla_host {
uint32_t reset_active:1; /* 3 */
uint32_t abort_isp_active:1; /* 4 */
uint32_t disable_risc_code_load:1; /* 5 */
-#ifdef __ia64__
- uint32_t use_pci_vchannel:1;
-#endif
} flags;
struct nvram nvram;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index da83034d4759..d4c3baec9172 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -4575,20 +4575,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
rval = 1;
}
-#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
- /*
- * The SN2 does not provide BIOS emulation which means you can't change
- * potentially bogus BIOS settings. Force the use of default settings
- * for link rate and frame size. Hope that the rest of the settings
- * are valid.
- */
- if (ia64_platform_is("sn2")) {
- nv->frame_payload_size = 2048;
- if (IS_QLA23XX(ha))
- nv->special_options[1] = BIT_7;
- }
-#endif
-
/* Reset Initialization control block */
memset(icb, 0, ha->init_cb_size);
diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig
deleted file mode 100644
index a6c443d31a3c..000000000000
--- a/drivers/sn/Kconfig
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Miscellaneous SN-specific devices
-#
-
-menu "SN Devices"
- depends on SGI_SN
-
-config SGI_IOC3
- tristate "SGI IOC3 Base IO support"
- default m
- ---help---
- This option enables basic support for the SGI IOC3-based Base IO
- controller card. This option does not enable any specific
- functions on such a card, but provides necessary infrastructure
- for other drivers to utilize.
-
- If you have an SGI Altix with an IOC3-based
- I/O controller or a PCI IOC3 serial card say Y.
- Otherwise say N.
-
-endmenu
diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile
deleted file mode 100644
index f0e809a38b2d..000000000000
--- a/drivers/sn/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Altix device drivers.
-#
-#
-
-obj-$(CONFIG_SGI_IOC3) += ioc3.o
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
deleted file mode 100644
index 358025af4918..000000000000
--- a/drivers/sn/ioc3.c
+++ /dev/null
@@ -1,844 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * SGI IOC3 master driver and IRQ demuxer
- *
- * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org>
- * Heavily based on similar work by:
- * Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
- * Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/ioc3.h>
-#include <linux/rwsem.h>
-#include <linux/slab.h>
-
-#define IOC3_PCI_SIZE 0x100000
-
-static LIST_HEAD(ioc3_devices);
-static int ioc3_counter;
-static DECLARE_RWSEM(ioc3_devices_rwsem);
-
-static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
-static struct ioc3_submodule *ioc3_ethernet;
-static DEFINE_RWLOCK(ioc3_submodules_lock);
-
-/* NIC probing code */
-
-#define GPCR_MLAN_EN 0x00200000 /* enable MCR to pin 8 */
-
-static inline unsigned mcr_pack(unsigned pulse, unsigned sample)
-{
- return (pulse << 10) | (sample << 2);
-}
-
-static int nic_wait(struct ioc3_driver_data *idd)
-{
- unsigned mcr;
-
- do {
- mcr = readl(&idd->vma->mcr);
- } while (!(mcr & 2));
-
- return mcr & 1;
-}
-
-static int nic_reset(struct ioc3_driver_data *idd)
-{
- int presence;
- unsigned long flags;
-
- local_irq_save(flags);
- writel(mcr_pack(500, 65), &idd->vma->mcr);
- presence = nic_wait(idd);
- local_irq_restore(flags);
-
- udelay(500);
-
- return presence;
-}
-
-static int nic_read_bit(struct ioc3_driver_data *idd)
-{
- int result;
- unsigned long flags;
-
- local_irq_save(flags);
- writel(mcr_pack(6, 13), &idd->vma->mcr);
- result = nic_wait(idd);
- local_irq_restore(flags);
-
- udelay(500);
-
- return result;
-}
-
-static void nic_write_bit(struct ioc3_driver_data *idd, int bit)
-{
- if (bit)
- writel(mcr_pack(6, 110), &idd->vma->mcr);
- else
- writel(mcr_pack(80, 30), &idd->vma->mcr);
-
- nic_wait(idd);
-}
-
-static unsigned nic_read_byte(struct ioc3_driver_data *idd)
-{
- unsigned result = 0;
- int i;
-
- for (i = 0; i < 8; i++)
- result = (result >> 1) | (nic_read_bit(idd) << 7);
-
- return result;
-}
-
-static void nic_write_byte(struct ioc3_driver_data *idd, int byte)
-{
- int i, bit;
-
- for (i = 8; i; i--) {
- bit = byte & 1;
- byte >>= 1;
-
- nic_write_bit(idd, bit);
- }
-}
-
-static unsigned long
-nic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr)
-{
- int a, b, index, disc;
-
- nic_reset(idd);
-
- /* Search ROM. */
- nic_write_byte(idd, 0xF0);
-
- /* Algorithm from ``Book of iButton Standards''. */
- for (index = 0, disc = 0; index < 64; index++) {
- a = nic_read_bit(idd);
- b = nic_read_bit(idd);
-
- if (a && b) {
- printk(KERN_WARNING "IOC3 NIC search failed.\n");
- *last = 0;
- return 0;
- }
-
- if (!a && !b) {
- if (index == *last) {
- addr |= 1UL << index;
- } else if (index > *last) {
- addr &= ~(1UL << index);
- disc = index;
- } else if ((addr & (1UL << index)) == 0)
- disc = index;
- nic_write_bit(idd, (addr>>index)&1);
- continue;
- } else {
- if (a)
- addr |= 1UL << index;
- else
- addr &= ~(1UL << index);
- nic_write_bit(idd, a);
- continue;
- }
- }
- *last = disc;
- return addr;
-}
-
-static void nic_addr(struct ioc3_driver_data *idd, unsigned long addr)
-{
- int index;
-
- nic_reset(idd);
- nic_write_byte(idd, 0xF0);
- for (index = 0; index < 64; index++) {
- nic_read_bit(idd);
- nic_read_bit(idd);
- nic_write_bit(idd, (addr>>index)&1);
- }
-}
-
-static void crc16_byte(unsigned int *crc, unsigned char db)
-{
- int i;
-
- for(i=0;i<8;i++) {
- *crc <<= 1;
- if((db^(*crc>>16)) & 1)
- *crc ^= 0x8005;
- db >>= 1;
- }
- *crc &= 0xFFFF;
-}
-
-static unsigned int crc16_area(unsigned char *dbs, int size, unsigned int crc)
-{
- while(size--)
- crc16_byte(&crc, *(dbs++));
- return crc;
-}
-
-static void crc8_byte(unsigned int *crc, unsigned char db)
-{
- int i,f;
-
- for(i=0;i<8;i++) {
- f = (*crc ^ db) & 1;
- *crc >>= 1;
- db >>= 1;
- if(f)
- *crc ^= 0x8c;
- }
- *crc &= 0xff;
-}
-
-static unsigned int crc8_addr(unsigned long addr)
-{
- int i;
- unsigned int crc = 0x00;
-
- for(i=0;i<8;i++)
- crc8_byte(&crc, addr>>(i<<3));
- return crc;
-}
-
-static void
-read_redir_page(struct ioc3_driver_data *idd, unsigned long addr, int page,
- unsigned char *redir, unsigned char *data)
-{
- int loops = 16, i;
-
- while(redir[page] != 0xFF) {
- page = redir[page]^0xFF;
- loops--;
- if(loops<0) {
- printk(KERN_ERR "IOC3: NIC circular redirection\n");
- return;
- }
- }
- loops = 3;
- while(loops>0) {
- nic_addr(idd, addr);
- nic_write_byte(idd, 0xF0);
- nic_write_byte(idd, (page << 5) & 0xE0);
- nic_write_byte(idd, (page >> 3) & 0x1F);
- for(i=0;i<0x20;i++)
- data[i] = nic_read_byte(idd);
- if(crc16_area(data, 0x20, 0x0000) == 0x800d)
- return;
- loops--;
- }
- printk(KERN_ERR "IOC3: CRC error in data page\n");
- for(i=0;i<0x20;i++)
- data[i] = 0x00;
-}
-
-static void
-read_redir_map(struct ioc3_driver_data *idd, unsigned long addr,
- unsigned char *redir)
-{
- int i,j,loops = 3,crc_ok;
- unsigned int crc;
-
- while(loops>0) {
- crc_ok = 1;
- nic_addr(idd, addr);
- nic_write_byte(idd, 0xAA);
- nic_write_byte(idd, 0x00);
- nic_write_byte(idd, 0x01);
- for(i=0;i<64;i+=8) {
- for(j=0;j<8;j++)
- redir[i+j] = nic_read_byte(idd);
- crc = crc16_area(redir+i, 8, (i==0)?0x8707:0x0000);
- crc16_byte(&crc, nic_read_byte(idd));
- crc16_byte(&crc, nic_read_byte(idd));
- if(crc != 0x800d)
- crc_ok = 0;
- }
- if(crc_ok)
- return;
- loops--;
- }
- printk(KERN_ERR "IOC3: CRC error in redirection page\n");
- for(i=0;i<64;i++)
- redir[i] = 0xFF;
-}
-
-static void read_nic(struct ioc3_driver_data *idd, unsigned long addr)
-{
- unsigned char redir[64];
- unsigned char data[64],part[32];
- int i,j;
-
- /* read redirections */
- read_redir_map(idd, addr, redir);
- /* read data pages */
- read_redir_page(idd, addr, 0, redir, data);
- read_redir_page(idd, addr, 1, redir, data+32);
- /* assemble the part # */
- j=0;
- for(i=0;i<19;i++)
- if(data[i+11] != ' ')
- part[j++] = data[i+11];
- for(i=0;i<6;i++)
- if(data[i+32] != ' ')
- part[j++] = data[i+32];
- part[j] = 0;
- /* skip Octane power supplies */
- if(!strncmp(part, "060-0035-", 9))
- return;
- if(!strncmp(part, "060-0038-", 9))
- return;
- strcpy(idd->nic_part, part);
- /* assemble the serial # */
- j=0;
- for(i=0;i<10;i++)
- if(data[i+1] != ' ')
- idd->nic_serial[j++] = data[i+1];
- idd->nic_serial[j] = 0;
-}
-
-static void read_mac(struct ioc3_driver_data *idd, unsigned long addr)
-{
- int i, loops = 3;
- unsigned char data[13];
-
- while(loops>0) {
- nic_addr(idd, addr);
- nic_write_byte(idd, 0xF0);
- nic_write_byte(idd, 0x00);
- nic_write_byte(idd, 0x00);
- nic_read_byte(idd);
- for(i=0;i<13;i++)
- data[i] = nic_read_byte(idd);
- if(crc16_area(data, 13, 0x0000) == 0x800d) {
- for(i=10;i>4;i--)
- idd->nic_mac[10-i] = data[i];
- return;
- }
- loops--;
- }
- printk(KERN_ERR "IOC3: CRC error in MAC address\n");
- for(i=0;i<6;i++)
- idd->nic_mac[i] = 0x00;
-}
-
-static void probe_nic(struct ioc3_driver_data *idd)
-{
- int save = 0, loops = 3;
- unsigned long first, addr;
-
- writel(GPCR_MLAN_EN, &idd->vma->gpcr_s);
-
- while(loops>0) {
- idd->nic_part[0] = 0;
- idd->nic_serial[0] = 0;
- addr = first = nic_find(idd, &save, 0);
- if(!first)
- return;
- while(1) {
- if(crc8_addr(addr))
- break;
- else {
- switch(addr & 0xFF) {
- case 0x0B:
- read_nic(idd, addr);
- break;
- case 0x09:
- case 0x89:
- case 0x91:
- read_mac(idd, addr);
- break;
- }
- }
- addr = nic_find(idd, &save, addr);
- if(addr == first)
- return;
- }
- loops--;
- }
- printk(KERN_ERR "IOC3: CRC error in NIC address\n");
-}
-
-/* Interrupts */
-
-static void write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&idd->ir_lock, flags);
- switch (which) {
- case IOC3_W_IES:
- writel(val, &idd->vma->sio_ies);
- break;
- case IOC3_W_IEC:
- writel(val, &idd->vma->sio_iec);
- break;
- }
- spin_unlock_irqrestore(&idd->ir_lock, flags);
-}
-static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd)
-{
- unsigned long flag;
- uint32_t intrs = 0;
-
- spin_lock_irqsave(&idd->ir_lock, flag);
- intrs = readl(&idd->vma->sio_ir);
- intrs &= readl(&idd->vma->sio_ies);
- spin_unlock_irqrestore(&idd->ir_lock, flag);
- return intrs;
-}
-
-static irqreturn_t ioc3_intr_io(int irq, void *arg)
-{
- unsigned long flags;
- struct ioc3_driver_data *idd = arg;
- int handled = 1, id;
- unsigned int pending;
-
- read_lock_irqsave(&ioc3_submodules_lock, flags);
-
- if(idd->dual_irq && readb(&idd->vma->eisr)) {
- /* send Ethernet IRQ to the driver */
- if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&
- ioc3_ethernet->intr) {
- handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,
- idd, 0);
- }
- }
- pending = get_pending_intrs(idd); /* look at the IO IRQs */
-
- for(id=0;id<IOC3_MAX_SUBMODULES;id++) {
- if(idd->active[id] && ioc3_submodules[id]
- && (pending & ioc3_submodules[id]->irq_mask)
- && ioc3_submodules[id]->intr) {
- write_ireg(idd, ioc3_submodules[id]->irq_mask,
- IOC3_W_IEC);
- if(!ioc3_submodules[id]->intr(ioc3_submodules[id],
- idd, pending & ioc3_submodules[id]->irq_mask))
- pending &= ~ioc3_submodules[id]->irq_mask;
- if (ioc3_submodules[id]->reset_mask)
- write_ireg(idd, ioc3_submodules[id]->irq_mask,
- IOC3_W_IES);
- }
- }
- read_unlock_irqrestore(&ioc3_submodules_lock, flags);
- if(pending) {
- printk(KERN_WARNING
- "IOC3: Pending IRQs 0x%08x discarded and disabled\n",pending);
- write_ireg(idd, pending, IOC3_W_IEC);
- handled = 1;
- }
- return handled?IRQ_HANDLED:IRQ_NONE;
-}
-
-static irqreturn_t ioc3_intr_eth(int irq, void *arg)
-{
- unsigned long flags;
- struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
- int handled = 1;
-
- if(!idd->dual_irq)
- return IRQ_NONE;
- read_lock_irqsave(&ioc3_submodules_lock, flags);
- if(ioc3_ethernet && idd->active[ioc3_ethernet->id]
- && ioc3_ethernet->intr)
- handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0);
- read_unlock_irqrestore(&ioc3_submodules_lock, flags);
- return handled?IRQ_HANDLED:IRQ_NONE;
-}
-
-void ioc3_enable(struct ioc3_submodule *is,
- struct ioc3_driver_data *idd, unsigned int irqs)
-{
- write_ireg(idd, irqs & is->irq_mask, IOC3_W_IES);
-}
-
-void ioc3_ack(struct ioc3_submodule *is, struct ioc3_driver_data *idd,
- unsigned int irqs)
-{
- writel(irqs & is->irq_mask, &idd->vma->sio_ir);
-}
-
-void ioc3_disable(struct ioc3_submodule *is,
- struct ioc3_driver_data *idd, unsigned int irqs)
-{
- write_ireg(idd, irqs & is->irq_mask, IOC3_W_IEC);
-}
-
-void ioc3_gpcr_set(struct ioc3_driver_data *idd, unsigned int val)
-{
- unsigned long flags;
- spin_lock_irqsave(&idd->gpio_lock, flags);
- writel(val, &idd->vma->gpcr_s);
- spin_unlock_irqrestore(&idd->gpio_lock, flags);
-}
-
-/* Keep it simple, stupid! */
-static int find_slot(void **tab, int max)
-{
- int i;
- for(i=0;i<max;i++)
- if(!(tab[i]))
- return i;
- return -1;
-}
-
-/* Register an IOC3 submodule */
-int ioc3_register_submodule(struct ioc3_submodule *is)
-{
- struct ioc3_driver_data *idd;
- int alloc_id;
- unsigned long flags;
-
- write_lock_irqsave(&ioc3_submodules_lock, flags);
- alloc_id = find_slot((void **)ioc3_submodules, IOC3_MAX_SUBMODULES);
- if(alloc_id != -1) {
- ioc3_submodules[alloc_id] = is;
- if(is->ethernet) {
- if(ioc3_ethernet==NULL)
- ioc3_ethernet=is;
- else
- printk(KERN_WARNING
- "IOC3 Ethernet module already registered!\n");
- }
- }
- write_unlock_irqrestore(&ioc3_submodules_lock, flags);
-
- if(alloc_id == -1) {
- printk(KERN_WARNING "Increase IOC3_MAX_SUBMODULES!\n");
- return -ENOMEM;
- }
-
- is->id=alloc_id;
-
- /* Initialize submodule for each IOC3 */
- if (!is->probe)
- return 0;
-
- down_read(&ioc3_devices_rwsem);
- list_for_each_entry(idd, &ioc3_devices, list) {
- /* set to 1 for IRQs in probe */
- idd->active[alloc_id] = 1;
- idd->active[alloc_id] = !is->probe(is, idd);
- }
- up_read(&ioc3_devices_rwsem);
-
- return 0;
-}
-
-/* Unregister an IOC3 submodule */
-void ioc3_unregister_submodule(struct ioc3_submodule *is)
-{
- struct ioc3_driver_data *idd;
- unsigned long flags;
-
- write_lock_irqsave(&ioc3_submodules_lock, flags);
- if(ioc3_submodules[is->id]==is)
- ioc3_submodules[is->id]=NULL;
- else
- printk(KERN_WARNING
- "IOC3 submodule %s has wrong ID.\n",is->name);
- if(ioc3_ethernet==is)
- ioc3_ethernet = NULL;
- write_unlock_irqrestore(&ioc3_submodules_lock, flags);
-
- /* Remove submodule for each IOC3 */
- down_read(&ioc3_devices_rwsem);
- list_for_each_entry(idd, &ioc3_devices, list)
- if(idd->active[is->id]) {
- if(is->remove)
- if(is->remove(is, idd))
- printk(KERN_WARNING
- "%s: IOC3 submodule %s remove failed "
- "for pci_dev %s.\n",
- __func__, module_name(is->owner),
- pci_name(idd->pdev));
- idd->active[is->id] = 0;
- if(is->irq_mask)
- write_ireg(idd, is->irq_mask, IOC3_W_IEC);
- }
- up_read(&ioc3_devices_rwsem);
-}
-
-/*********************
- * Device management *
- *********************/
-
-static char *ioc3_class_names[] = { "unknown", "IP27 BaseIO", "IP30 system",
- "MENET 1/2/3", "MENET 4", "CADduo", "Altix Serial" };
-
-static int ioc3_class(struct ioc3_driver_data *idd)
-{
- int res = IOC3_CLASS_NONE;
- /* NIC-based logic */
- if(!strncmp(idd->nic_part, "030-0891-", 9))
- res = IOC3_CLASS_BASE_IP30;
- if(!strncmp(idd->nic_part, "030-1155-", 9))
- res = IOC3_CLASS_CADDUO;
- if(!strncmp(idd->nic_part, "030-1657-", 9))
- res = IOC3_CLASS_SERIAL;
- if(!strncmp(idd->nic_part, "030-1664-", 9))
- res = IOC3_CLASS_SERIAL;
- /* total random heuristics */
-#ifdef CONFIG_SGI_IP27
- if(!idd->nic_part[0])
- res = IOC3_CLASS_BASE_IP27;
-#endif
- /* print educational message */
- printk(KERN_INFO "IOC3 part: [%s], serial: [%s] => class %s\n",
- idd->nic_part, idd->nic_serial, ioc3_class_names[res]);
- return res;
-}
-/* Adds a new instance of an IOC3 card */
-static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
- struct ioc3_driver_data *idd;
- uint32_t pcmd;
- int ret, id;
-
- /* Enable IOC3 and take ownership of it */
- if ((ret = pci_enable_device(pdev))) {
- printk(KERN_WARNING
- "%s: Failed to enable IOC3 device for pci_dev %s.\n",
- __func__, pci_name(pdev));
- goto out;
- }
- pci_set_master(pdev);
-
-#ifdef USE_64BIT_DMA
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
- if (!ret) {
- ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
- if (ret < 0) {
- printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA "
- "for consistent allocations\n",
- __func__);
- }
- }
-#endif
-
- /* Set up per-IOC3 data */
- idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
- if (!idd) {
- printk(KERN_WARNING
- "%s: Failed to allocate IOC3 data for pci_dev %s.\n",
- __func__, pci_name(pdev));
- ret = -ENODEV;
- goto out_idd;
- }
- spin_lock_init(&idd->ir_lock);
- spin_lock_init(&idd->gpio_lock);
- idd->pdev = pdev;
-
- /* Map all IOC3 registers. These are shared between subdevices
- * so the main IOC3 module manages them.
- */
- idd->pma = pci_resource_start(pdev, 0);
- if (!idd->pma) {
- printk(KERN_WARNING
- "%s: Unable to find IOC3 resource "
- "for pci_dev %s.\n",
- __func__, pci_name(pdev));
- ret = -ENODEV;
- goto out_pci;
- }
- if (!request_mem_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) {
- printk(KERN_WARNING
- "%s: Unable to request IOC3 region "
- "for pci_dev %s.\n",
- __func__, pci_name(pdev));
- ret = -ENODEV;
- goto out_pci;
- }
- idd->vma = ioremap(idd->pma, IOC3_PCI_SIZE);
- if (!idd->vma) {
- printk(KERN_WARNING
- "%s: Unable to remap IOC3 region "
- "for pci_dev %s.\n",
- __func__, pci_name(pdev));
- ret = -ENODEV;
- goto out_misc_region;
- }
-
- /* Track PCI-device specific data */
- pci_set_drvdata(pdev, idd);
- down_write(&ioc3_devices_rwsem);
- list_add_tail(&idd->list, &ioc3_devices);
- idd->id = ioc3_counter++;
- up_write(&ioc3_devices_rwsem);
-
- idd->gpdr_shadow = readl(&idd->vma->gpdr);
-
- /* Read IOC3 NIC contents */
- probe_nic(idd);
-
- /* Detect IOC3 class */
- idd->class = ioc3_class(idd);
-
- /* Initialize IOC3 */
- pci_read_config_dword(pdev, PCI_COMMAND, &pcmd);
- pci_write_config_dword(pdev, PCI_COMMAND,
- pcmd | PCI_COMMAND_MEMORY |
- PCI_COMMAND_PARITY | PCI_COMMAND_SERR |
- PCI_SCR_DROP_MODE_EN);
-
- write_ireg(idd, ~0, IOC3_W_IEC);
- writel(~0, &idd->vma->sio_ir);
-
- /* Set up IRQs */
- if(idd->class == IOC3_CLASS_BASE_IP30
- || idd->class == IOC3_CLASS_BASE_IP27) {
- writel(0, &idd->vma->eier);
- writel(~0, &idd->vma->eisr);
-
- idd->dual_irq = 1;
- if (!request_irq(pdev->irq, ioc3_intr_eth, IRQF_SHARED,
- "ioc3-eth", (void *)idd)) {
- idd->irq_eth = pdev->irq;
- } else {
- printk(KERN_WARNING
- "%s : request_irq fails for IRQ 0x%x\n ",
- __func__, pdev->irq);
- }
- if (!request_irq(pdev->irq+2, ioc3_intr_io, IRQF_SHARED,
- "ioc3-io", (void *)idd)) {
- idd->irq_io = pdev->irq+2;
- } else {
- printk(KERN_WARNING
- "%s : request_irq fails for IRQ 0x%x\n ",
- __func__, pdev->irq+2);
- }
- } else {
- if (!request_irq(pdev->irq, ioc3_intr_io, IRQF_SHARED,
- "ioc3", (void *)idd)) {
- idd->irq_io = pdev->irq;
- } else {
- printk(KERN_WARNING
- "%s : request_irq fails for IRQ 0x%x\n ",
- __func__, pdev->irq);
- }
- }
-
- /* Add this IOC3 to all submodules */
- for(id=0;id<IOC3_MAX_SUBMODULES;id++)
- if(ioc3_submodules[id] && ioc3_submodules[id]->probe) {
- idd->active[id] = 1;
- idd->active[id] = !ioc3_submodules[id]->probe
- (ioc3_submodules[id], idd);
- }
-
- printk(KERN_INFO "IOC3 Master Driver loaded for %s\n", pci_name(pdev));
-
- return 0;
-
-out_misc_region:
- release_mem_region(idd->pma, IOC3_PCI_SIZE);
-out_pci:
- kfree(idd);
-out_idd:
- pci_disable_device(pdev);
-out:
- return ret;
-}
-
-/* Removes a particular instance of an IOC3 card. */
-static void ioc3_remove(struct pci_dev *pdev)
-{
- int id;
- struct ioc3_driver_data *idd;
-
- idd = pci_get_drvdata(pdev);
-
- /* Remove this IOC3 from all submodules */
- for(id=0;id<IOC3_MAX_SUBMODULES;id++)
- if(idd->active[id]) {
- if(ioc3_submodules[id] && ioc3_submodules[id]->remove)
- if(ioc3_submodules[id]->remove(ioc3_submodules[id],
- idd))
- printk(KERN_WARNING
- "%s: IOC3 submodule 0x%s remove failed "
- "for pci_dev %s.\n",
- __func__,
- module_name(ioc3_submodules[id]->owner),
- pci_name(pdev));
- idd->active[id] = 0;
- }
-
- /* Clear and disable all IRQs */
- write_ireg(idd, ~0, IOC3_W_IEC);
- writel(~0, &idd->vma->sio_ir);
-
- /* Release resources */
- free_irq(idd->irq_io, (void *)idd);
- if(idd->dual_irq)
- free_irq(idd->irq_eth, (void *)idd);
- iounmap(idd->vma);
- release_mem_region(idd->pma, IOC3_PCI_SIZE);
-
- /* Disable IOC3 and relinquish */
- pci_disable_device(pdev);
-
- /* Remove and free driver data */
- down_write(&ioc3_devices_rwsem);
- list_del(&idd->list);
- up_write(&ioc3_devices_rwsem);
- kfree(idd);
-}
-
-static struct pci_device_id ioc3_id_table[] = {
- {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID},
- {0}
-};
-
-static struct pci_driver ioc3_driver = {
- .name = "IOC3",
- .id_table = ioc3_id_table,
- .probe = ioc3_probe,
- .remove = ioc3_remove,
-};
-
-MODULE_DEVICE_TABLE(pci, ioc3_id_table);
-
-/*********************
- * Module management *
- *********************/
-
-/* Module load */
-static int __init ioc3_init(void)
-{
- if (ia64_platform_is("sn2"))
- return pci_register_driver(&ioc3_driver);
- return -ENODEV;
-}
-
-/* Module unload */
-static void __exit ioc3_exit(void)
-{
- pci_unregister_driver(&ioc3_driver);
-}
-
-module_init(ioc3_init);
-module_exit(ioc3_exit);
-
-MODULE_AUTHOR("Stanislaw Skowronek <skylark@linux-mips.org>");
-MODULE_DESCRIPTION("PCI driver for SGI IOC3");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL_GPL(ioc3_register_submodule);
-EXPORT_SYMBOL_GPL(ioc3_unregister_submodule);
-EXPORT_SYMBOL_GPL(ioc3_ack);
-EXPORT_SYMBOL_GPL(ioc3_gpcr_set);
-EXPORT_SYMBOL_GPL(ioc3_disable);
-EXPORT_SYMBOL_GPL(ioc3_enable);
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 3083dbae35f7..2f631501c75f 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -855,16 +855,6 @@ config SERIAL_CPM_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
-config SERIAL_SGI_L1_CONSOLE
- bool "SGI Altix L1 serial console support"
- depends on IA64_GENERIC || IA64_SGI_SN2
- select SERIAL_CORE
- select SERIAL_CORE_CONSOLE
- help
- If you have an SGI Altix and you would like to use the system
- controller serial port as your console (you want this!),
- say Y. Otherwise, say N.
-
config SERIAL_PIC32
tristate "Microchip PIC32 serial support"
depends on MACH_PIC32
@@ -982,23 +972,6 @@ config SERIAL_JSM
To compile this driver as a module, choose M here: the
module will be called jsm.
-config SERIAL_SGI_IOC4
- tristate "SGI IOC4 controller serial support"
- depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4
- select SERIAL_CORE
- help
- If you have an SGI Altix with an IOC4 based Base IO card
- and wish to use the serial ports on this card, say Y.
- Otherwise, say N.
-
-config SERIAL_SGI_IOC3
- tristate "SGI Altix IOC3 serial support"
- depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
- select SERIAL_CORE
- help
- If you have an SGI Altix with an IOC3 serial card,
- say Y or M. Otherwise, say N.
-
config SERIAL_MSM
tristate "MSM on-chip serial port support"
depends on ARCH_QCOM
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 15a0fccadf7e..d2f44879384e 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -41,7 +41,6 @@ obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
-obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
obj-$(CONFIG_SERIAL_IMX) += imx.o
obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
@@ -53,8 +52,6 @@ obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
-obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
-obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
deleted file mode 100644
index d8a1cdd6a53d..000000000000
--- a/drivers/tty/serial/ioc3_serial.c
+++ /dev/null
@@ -1,2195 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
- */
-
-/*
- * This file contains a module version of the ioc3 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/serial_core.h>
-#include <linux/ioc3.h>
-#include <linux/slab.h>
-
-/*
- * Interesting things about the ioc3
- */
-
-#define LOGICAL_PORTS 2 /* rs232(0) and rs422(1) */
-#define PORTS_PER_CARD 2
-#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
-#define MAX_CARDS 8
-#define MAX_LOGICAL_PORTS (LOGICAL_PORTS_PER_CARD * MAX_CARDS)
-
-/* determine given the sio_ir what port it applies to */
-#define GET_PORT_FROM_SIO_IR(_x) (_x & SIO_IR_SA) ? 0 : 1
-
-
-/*
- * we have 2 logical ports (rs232, rs422) for each physical port
- * evens are rs232, odds are rs422
- */
-#define GET_PHYSICAL_PORT(_x) ((_x) >> 1)
-#define GET_LOGICAL_PORT(_x) ((_x) & 1)
-#define IS_PHYSICAL_PORT(_x) !((_x) & 1)
-#define IS_RS232(_x) !((_x) & 1)
-
-static unsigned int Num_of_ioc3_cards;
-static unsigned int Submodule_slot;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...) ;
-//#define DPRINT_CONFIG(_x...) printk _x
-#define NOT_PROGRESS() ;
-//#define NOT_PROGRESS() printk("%s : fails %d\n", __func__, __LINE__)
-
-/* number of characters we want to transmit to the lower level at a time */
-#define MAX_CHARS 256
-#define FIFO_SIZE (MAX_CHARS-1) /* it's a uchar */
-
-/* Device name we're using */
-#define DEVICE_NAME "ttySIOC"
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR 116
-
-/* flags for next_char_state */
-#define NCS_BREAK 0x1
-#define NCS_PARITY 0x2
-#define NCS_FRAMING 0x4
-#define NCS_OVERRUN 0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED 1200
-#define MAX_BAUD_SUPPORTED 115200
-
-/* protocol types supported */
-#define PROTO_RS232 0
-#define PROTO_RS422 1
-
-/* Notification types */
-#define N_DATA_READY 0x01
-#define N_OUTPUT_LOWAT 0x02
-#define N_BREAK 0x04
-#define N_PARITY_ERROR 0x08
-#define N_FRAMING_ERROR 0x10
-#define N_OVERRUN_ERROR 0x20
-#define N_DDCD 0x40
-#define N_DCTS 0x80
-
-#define N_ALL_INPUT (N_DATA_READY | N_BREAK \
- | N_PARITY_ERROR | N_FRAMING_ERROR \
- | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS (N_PARITY_ERROR | N_FRAMING_ERROR \
- | N_OVERRUN_ERROR)
-
-#define N_ALL (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK \
- | N_PARITY_ERROR | N_FRAMING_ERROR \
- | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_CLK_SPEED(prediv) ((22000000 << 1) / prediv)
-#define SER_DIVISOR(x, clk) (((clk) + (x) * 8) / ((x) * 16))
-#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
- | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS (UART_LCR_STOP)
-
-#define PENDING(_a, _p) (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
-
-#define RING_BUF_SIZE 4096
-#define BUF_SIZE_BIT SBBR_L_SIZE
-#define PROD_CONS_MASK PROD_CONS_PTR_4K
-
-#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
-
-/* driver specific - one per card */
-struct ioc3_card {
- struct {
- /* uart ports are allocated here */
- struct uart_port icp_uart_port[LOGICAL_PORTS];
- /* the ioc3_port used for this port */
- struct ioc3_port *icp_port;
- } ic_port[PORTS_PER_CARD];
- /* currently enabled interrupts */
- uint32_t ic_enable;
-};
-
-/* Local port info for each IOC3 serial port */
-struct ioc3_port {
- /* handy reference material */
- struct uart_port *ip_port;
- struct ioc3_card *ip_card;
- struct ioc3_driver_data *ip_idd;
- struct ioc3_submodule *ip_is;
-
- /* pci mem addresses for this port */
- struct ioc3_serialregs __iomem *ip_serial_regs;
- struct ioc3_uartregs __iomem *ip_uart_regs;
-
- /* Ring buffer page for this port */
- dma_addr_t ip_dma_ringbuf;
- /* vaddr of ring buffer */
- struct ring_buffer *ip_cpu_ringbuf;
-
- /* Rings for this port */
- struct ring *ip_inring;
- struct ring *ip_outring;
-
- /* Hook to port specific values */
- struct port_hooks *ip_hooks;
-
- spinlock_t ip_lock;
-
- /* Various rx/tx parameters */
- int ip_baud;
- int ip_tx_lowat;
- int ip_rx_timeout;
-
- /* Copy of notification bits */
- int ip_notify;
-
- /* Shadow copies of various registers so we don't need to PIO
- * read them constantly
- */
- uint32_t ip_sscr;
- uint32_t ip_tx_prod;
- uint32_t ip_rx_cons;
- unsigned char ip_flags;
-};
-
-/* tx low water mark. We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY 1000
-#define TX_LOWAT_HZ (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH 0x01
- /* used to signify that we have turned off the rx_high
- * temporarily - we need to drain the fifo and don't
- * want to get blasted with interrupts.
- */
-#define DCD_ON 0x02
- /* DCD state is on */
-#define LOWAT_WRITTEN 0x04
-#define READ_ABORTED 0x08
- /* the read was aborted - used to avaoid infinate looping
- * in the interrupt handler
- */
-#define INPUT_ENABLE 0x10
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct port_hooks {
- uint32_t intr_delta_dcd;
- uint32_t intr_delta_cts;
- uint32_t intr_tx_mt;
- uint32_t intr_rx_timer;
- uint32_t intr_rx_high;
- uint32_t intr_tx_explicit;
- uint32_t intr_clear;
- uint32_t intr_all;
- char rs422_select_pin;
-};
-
-static struct port_hooks hooks_array[PORTS_PER_CARD] = {
- /* values for port A */
- {
- .intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
- .intr_delta_cts = SIO_IR_SA_DELTA_CTS,
- .intr_tx_mt = SIO_IR_SA_TX_MT,
- .intr_rx_timer = SIO_IR_SA_RX_TIMER,
- .intr_rx_high = SIO_IR_SA_RX_HIGH,
- .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
- .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
- | SIO_IR_SA_RX_HIGH
- | SIO_IR_SA_RX_TIMER
- | SIO_IR_SA_DELTA_DCD
- | SIO_IR_SA_DELTA_CTS
- | SIO_IR_SA_INT
- | SIO_IR_SA_TX_EXPLICIT
- | SIO_IR_SA_MEMERR),
- .intr_all = SIO_IR_SA,
- .rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
- },
-
- /* values for port B */
- {
- .intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
- .intr_delta_cts = SIO_IR_SB_DELTA_CTS,
- .intr_tx_mt = SIO_IR_SB_TX_MT,
- .intr_rx_timer = SIO_IR_SB_RX_TIMER,
- .intr_rx_high = SIO_IR_SB_RX_HIGH,
- .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
- .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
- | SIO_IR_SB_RX_HIGH
- | SIO_IR_SB_RX_TIMER
- | SIO_IR_SB_DELTA_DCD
- | SIO_IR_SB_DELTA_CTS
- | SIO_IR_SB_INT
- | SIO_IR_SB_TX_EXPLICIT
- | SIO_IR_SB_MEMERR),
- .intr_all = SIO_IR_SB,
- .rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
- }
-};
-
-struct ring_entry {
- union {
- struct {
- uint32_t alldata;
- uint32_t allsc;
- } all;
- struct {
- char data[4]; /* data bytes */
- char sc[4]; /* status/control */
- } s;
- } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
- ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc u.s.sc
-#define ring_data u.s.data
-#define ring_allsc u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
- struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
- struct ring TX_A;
- struct ring RX_A;
- struct ring TX_B;
- struct ring RX_B;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh) &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* for Infinite loop detection */
-#define MAXITER 10000000
-
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc3_port *port, int baud)
-{
- int divisor;
- int actual_baud;
- int diff;
- int lcr, prediv;
- struct ioc3_uartregs __iomem *uart;
-
- for (prediv = 6; prediv < 64; prediv++) {
- divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
- if (!divisor)
- continue; /* invalid divisor */
- actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
-
- diff = actual_baud - baud;
- if (diff < 0)
- diff = -diff;
-
- /* if we're within 1% we've found a match */
- if (diff * 100 <= actual_baud)
- break;
- }
-
- /* if the above loop completed, we didn't match
- * the baud rate. give up.
- */
- if (prediv == 64) {
- NOT_PROGRESS();
- return 1;
- }
-
- uart = port->ip_uart_regs;
- lcr = readb(&uart->iu_lcr);
-
- writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
- writeb((unsigned char)divisor, &uart->iu_dll);
- writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
- writeb((unsigned char)prediv, &uart->iu_scr);
- writeb((unsigned char)lcr, &uart->iu_lcr);
-
- return 0;
-}
-
-/**
- * get_ioc3_port - given a uart port, return the control structure
- * @the_port: uart port to find
- */
-static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
-{
- struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
- struct ioc3_card *card_ptr = idd->data[Submodule_slot];
- int ii, jj;
-
- if (!card_ptr) {
- NOT_PROGRESS();
- return NULL;
- }
- for (ii = 0; ii < PORTS_PER_CARD; ii++) {
- for (jj = 0; jj < LOGICAL_PORTS; jj++) {
- if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
- return card_ptr->ic_port[ii].icp_port;
- }
- }
- NOT_PROGRESS();
- return NULL;
-}
-
-/**
- * port_init - Initialize the sio and ioc3 hardware for a given port
- * called per port from attach...
- * @port: port to initialize
- */
-static inline int port_init(struct ioc3_port *port)
-{
- uint32_t sio_cr;
- struct port_hooks *hooks = port->ip_hooks;
- struct ioc3_uartregs __iomem *uart;
- int reset_loop_counter = 0xfffff;
- struct ioc3_driver_data *idd = port->ip_idd;
-
- /* Idle the IOC3 serial interface */
- writel(SSCR_RESET, &port->ip_serial_regs->sscr);
-
- /* Wait until any pending bus activity for this port has ceased */
- do {
- sio_cr = readl(&idd->vma->sio_cr);
- if (reset_loop_counter-- <= 0) {
- printk(KERN_WARNING
- "IOC3 unable to come out of reset"
- " scr 0x%x\n", sio_cr);
- return -1;
- }
- } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
- (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
- || sio_cr == SIO_CR_ARB_DIAG_TXB
- || sio_cr == SIO_CR_ARB_DIAG_RXA
- || sio_cr == SIO_CR_ARB_DIAG_RXB));
-
- /* Finish reset sequence */
- writel(0, &port->ip_serial_regs->sscr);
-
- /* Once RESET is done, reload cached tx_prod and rx_cons values
- * and set rings to empty by making prod == cons
- */
- port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
- writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
- port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
- writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
- /* Disable interrupts for this 16550 */
- uart = port->ip_uart_regs;
- writeb(0, &uart->iu_lcr);
- writeb(0, &uart->iu_ier);
-
- /* Set the default baud */
- set_baud(port, port->ip_baud);
-
- /* Set line control to 8 bits no parity */
- writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
- /* UART_LCR_STOP == 1 stop */
-
- /* Enable the FIFOs */
- writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
- /* then reset 16550 FIFOs */
- writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
- &uart->iu_fcr);
-
- /* Clear modem control register */
- writeb(0, &uart->iu_mcr);
-
- /* Clear deltas in modem status register */
- writel(0, &port->ip_serial_regs->shadow);
-
- /* Only do this once per port pair */
- if (port->ip_hooks == &hooks_array[0]) {
- unsigned long ring_pci_addr;
- uint32_t __iomem *sbbr_l, *sbbr_h;
-
- sbbr_l = &idd->vma->sbbr_l;
- sbbr_h = &idd->vma->sbbr_h;
- ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
- DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
- __func__, (void *)ring_pci_addr));
-
- writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
- writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
- }
-
- /* Set the receive timeout value to 10 msec */
- writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
- /* Set rx threshold, enable DMA */
- /* Set high water mark at 3/4 of full ring */
- port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
-
- /* uart experiences pauses at high baud rate reducing actual
- * throughput by 10% or so unless we enable high speed polling
- * XXX when this hardware bug is resolved we should revert to
- * normal polling speed
- */
- port->ip_sscr |= SSCR_HIGH_SPD;
-
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
- /* Disable and clear all serial related interrupt bits */
- port->ip_card->ic_enable &= ~hooks->intr_clear;
- ioc3_disable(port->ip_is, idd, hooks->intr_clear);
- ioc3_ack(port->ip_is, idd, hooks->intr_clear);
- return 0;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc3_port *port, uint32_t mask)
-{
- if ((port->ip_card->ic_enable & mask) != mask) {
- port->ip_card->ic_enable |= mask;
- ioc3_enable(port->ip_is, port->ip_idd, mask);
- }
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc3_port *port)
-{
- int spiniter = 0;
-
- port->ip_flags = INPUT_ENABLE;
-
- /* Pause the DMA interface if necessary */
- if (port->ip_sscr & SSCR_DMA_EN) {
- writel(port->ip_sscr | SSCR_DMA_PAUSE,
- &port->ip_serial_regs->sscr);
- while ((readl(&port->ip_serial_regs->sscr)
- & SSCR_PAUSE_STATE) == 0) {
- spiniter++;
- if (spiniter > MAXITER) {
- NOT_PROGRESS();
- return -1;
- }
- }
- }
-
- /* Reset the input fifo. If the uart received chars while the port
- * was closed and DMA is not enabled, the uart may have a bunch of
- * chars hanging around in its rx fifo which will not be discarded
- * by rclr in the upper layer. We must get rid of them here.
- */
- writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
- &port->ip_uart_regs->iu_fcr);
-
- writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
- /* UART_LCR_STOP == 1 stop */
-
- /* Re-enable DMA, set default threshold to intr whenever there is
- * data available.
- */
- port->ip_sscr &= ~SSCR_RX_THRESHOLD;
- port->ip_sscr |= 1; /* default threshold */
-
- /* Plug in the new sscr. This implicitly clears the DMA_PAUSE
- * flag if it was set above
- */
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- port->ip_tx_lowat = 1;
- return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
-{
- int threshold;
-
- port->ip_rx_timeout = timeout;
-
- /* Timeout is in ticks. Let's figure out how many chars we
- * can receive at the current baud rate in that interval
- * and set the rx threshold to that amount. There are 4 chars
- * per ring entry, so we'll divide the number of chars that will
- * arrive in timeout by 4.
- * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
- */
- threshold = timeout * port->ip_baud / 4000;
- if (threshold == 0)
- threshold = 1; /* otherwise we'll intr all the time! */
-
- if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
- return 1;
-
- port->ip_sscr &= ~SSCR_RX_THRESHOLD;
- port->ip_sscr |= threshold;
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
- /* Now set the rx timeout to the given value
- * again timeout * SRTR_HZ / HZ
- */
- timeout = timeout * SRTR_HZ / 100;
- if (timeout > SRTR_CNT)
- timeout = SRTR_CNT;
- writel(timeout, &port->ip_serial_regs->srtr);
- return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc3_port *port,
- int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
- char lcr, sizebits;
- int spiniter = 0;
-
- DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
- "parodd %d\n",
- __func__, ((struct uart_port *)port->ip_port)->line,
- baud, byte_size, stop_bits, parenb, parodd));
-
- if (set_baud(port, baud))
- return 1;
-
- switch (byte_size) {
- case 5:
- sizebits = UART_LCR_WLEN5;
- break;
- case 6:
- sizebits = UART_LCR_WLEN6;
- break;
- case 7:
- sizebits = UART_LCR_WLEN7;
- break;
- case 8:
- sizebits = UART_LCR_WLEN8;
- break;
- default:
- return 1;
- }
-
- /* Pause the DMA interface if necessary */
- if (port->ip_sscr & SSCR_DMA_EN) {
- writel(port->ip_sscr | SSCR_DMA_PAUSE,
- &port->ip_serial_regs->sscr);
- while ((readl(&port->ip_serial_regs->sscr)
- & SSCR_PAUSE_STATE) == 0) {
- spiniter++;
- if (spiniter > MAXITER)
- return -1;
- }
- }
-
- /* Clear relevant fields in lcr */
- lcr = readb(&port->ip_uart_regs->iu_lcr);
- lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
- UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
- /* Set byte size in lcr */
- lcr |= sizebits;
-
- /* Set parity */
- if (parenb) {
- lcr |= UART_LCR_PARITY;
- if (!parodd)
- lcr |= UART_LCR_EPAR;
- }
-
- /* Set stop bits */
- if (stop_bits)
- lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
- writeb(lcr, &port->ip_uart_regs->iu_lcr);
-
- /* Re-enable the DMA interface if necessary */
- if (port->ip_sscr & SSCR_DMA_EN) {
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
- port->ip_baud = baud;
-
- /* When we get within this number of ring entries of filling the
- * entire ring on tx, place an EXPLICIT intr to generate a lowat
- * notification when output has drained.
- */
- port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
- if (port->ip_tx_lowat == 0)
- port->ip_tx_lowat = 1;
-
- set_rx_timeout(port, 2);
- return 0;
-}
-
-/**
- * do_write - Write bytes to the port. Returns the number of bytes
- * actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc3_port *port, char *buf, int len)
-{
- int prod_ptr, cons_ptr, total = 0;
- struct ring *outring;
- struct ring_entry *entry;
- struct port_hooks *hooks = port->ip_hooks;
-
- BUG_ON(!(len >= 0));
-
- prod_ptr = port->ip_tx_prod;
- cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
- outring = port->ip_outring;
-
- /* Maintain a 1-entry red-zone. The ring buffer is full when
- * (cons - prod) % ring_size is 1. Rather than do this subtraction
- * in the body of the loop, I'll do it now.
- */
- cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
- /* Stuff the bytes into the output */
- while ((prod_ptr != cons_ptr) && (len > 0)) {
- int xx;
-
- /* Get 4 bytes (one ring entry) at a time */
- entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
- /* Invalidate all entries */
- entry->ring_allsc = 0;
-
- /* Copy in some bytes */
- for (xx = 0; (xx < 4) && (len > 0); xx++) {
- entry->ring_data[xx] = *buf++;
- entry->ring_sc[xx] = TXCB_VALID;
- len--;
- total++;
- }
-
- /* If we are within some small threshold of filling up the
- * entire ring buffer, we must place an EXPLICIT intr here
- * to generate a lowat interrupt in case we subsequently
- * really do fill up the ring and the caller goes to sleep.
- * No need to place more than one though.
- */
- if (!(port->ip_flags & LOWAT_WRITTEN) &&
- ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
- <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
- port->ip_flags |= LOWAT_WRITTEN;
- entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
- }
-
- /* Go on to next entry */
- prod_ptr += sizeof(struct ring_entry);
- prod_ptr &= PROD_CONS_MASK;
- }
-
- /* If we sent something, start DMA if necessary */
- if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
- port->ip_sscr |= SSCR_DMA_EN;
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
-
- /* Store the new producer pointer. If tx is disabled, we stuff the
- * data into the ring buffer, but we don't actually start tx.
- */
- if (!uart_tx_stopped(port->ip_port)) {
- writel(prod_ptr, &port->ip_serial_regs->stpir);
-
- /* If we are now transmitting, enable tx_mt interrupt so we
- * can disable DMA if necessary when the tx finishes.
- */
- if (total > 0)
- enable_intrs(port, hooks->intr_tx_mt);
- }
- port->ip_tx_prod = prod_ptr;
-
- return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
-{
- if (port->ip_card->ic_enable & mask) {
- ioc3_disable(port->ip_is, port->ip_idd, mask);
- port->ip_card->ic_enable &= ~mask;
- }
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc3_port *port, int mask, int set_on)
-{
- struct port_hooks *hooks = port->ip_hooks;
- uint32_t intrbits, sscrbits;
-
- BUG_ON(!mask);
-
- intrbits = sscrbits = 0;
-
- if (mask & N_DATA_READY)
- intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
- if (mask & N_OUTPUT_LOWAT)
- intrbits |= hooks->intr_tx_explicit;
- if (mask & N_DDCD) {
- intrbits |= hooks->intr_delta_dcd;
- sscrbits |= SSCR_RX_RING_DCD;
- }
- if (mask & N_DCTS)
- intrbits |= hooks->intr_delta_cts;
-
- if (set_on) {
- enable_intrs(port, intrbits);
- port->ip_notify |= mask;
- port->ip_sscr |= sscrbits;
- } else {
- disable_intrs(port, intrbits);
- port->ip_notify &= ~mask;
- port->ip_sscr &= ~sscrbits;
- }
-
- /* We require DMA if either DATA_READY or DDCD notification is
- * currently requested. If neither of these is requested and
- * there is currently no tx in progress, DMA may be disabled.
- */
- if (port->ip_notify & (N_DATA_READY | N_DDCD))
- port->ip_sscr |= SSCR_DMA_EN;
- else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
- port->ip_sscr &= ~SSCR_DMA_EN;
-
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
- int mask1, int mask2)
-{
- struct ioc3_port *port = get_ioc3_port(the_port);
- uint32_t shadow;
- int spiniter = 0;
- char mcr;
-
- if (!port)
- return -1;
-
- /* Pause the DMA interface if necessary */
- if (port->ip_sscr & SSCR_DMA_EN) {
- writel(port->ip_sscr | SSCR_DMA_PAUSE,
- &port->ip_serial_regs->sscr);
- while ((readl(&port->ip_serial_regs->sscr)
- & SSCR_PAUSE_STATE) == 0) {
- spiniter++;
- if (spiniter > MAXITER)
- return -1;
- }
- }
- shadow = readl(&port->ip_serial_regs->shadow);
- mcr = (shadow & 0xff000000) >> 24;
-
- /* Set new value */
- mcr |= mask1;
- shadow |= mask2;
- writeb(mcr, &port->ip_uart_regs->iu_mcr);
- writel(shadow, &port->ip_serial_regs->shadow);
-
- /* Re-enable the DMA interface if necessary */
- if (port->ip_sscr & SSCR_DMA_EN) {
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
- return 0;
-}
-
-/**
- * ioc3_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc3_set_proto(struct ioc3_port *port, int proto)
-{
- struct port_hooks *hooks = port->ip_hooks;
-
- switch (proto) {
- default:
- case PROTO_RS232:
- /* Clear the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs232\n", __func__));
- writel(0, (&port->ip_idd->vma->gppr[0]
- + hooks->rs422_select_pin));
- break;
-
- case PROTO_RS422:
- /* Set the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs422\n", __func__));
- writel(1, (&port->ip_idd->vma->gppr[0]
- + hooks->rs422_select_pin));
- break;
- }
- return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with the_port->lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
- int xmit_count, tail, head;
- int result;
- char *start;
- struct tty_struct *tty;
- struct ioc3_port *port = get_ioc3_port(the_port);
- struct uart_state *state;
-
- if (!the_port)
- return;
- if (!port)
- return;
-
- state = the_port->state;
- tty = state->port.tty;
-
- if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
- /* Nothing to do or hw stopped */
- set_notification(port, N_ALL_OUTPUT, 0);
- return;
- }
-
- head = state->xmit.head;
- tail = state->xmit.tail;
- start = (char *)&state->xmit.buf[tail];
-
- /* write out all the data or until the end of the buffer */
- xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
- if (xmit_count > 0) {
- result = do_write(port, start, xmit_count);
- if (result > 0) {
- /* booking */
- xmit_count -= result;
- the_port->icount.tx += result;
- /* advance the pointers */
- tail += result;
- tail &= UART_XMIT_SIZE - 1;
- state->xmit.tail = tail;
- start = (char *)&state->xmit.buf[tail];
- }
- }
- if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(the_port);
-
- if (uart_circ_empty(&state->xmit)) {
- set_notification(port, N_OUTPUT_LOWAT, 0);
- } else {
- set_notification(port, N_OUTPUT_LOWAT, 1);
- }
-}
-
-/**
- * ioc3_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc3_change_speed(struct uart_port *the_port,
- struct ktermios *new_termios, struct ktermios *old_termios)
-{
- struct ioc3_port *port = get_ioc3_port(the_port);
- unsigned int cflag, iflag;
- int baud;
- int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
- struct uart_state *state = the_port->state;
-
- cflag = new_termios->c_cflag;
- iflag = new_termios->c_iflag;
-
- switch (cflag & CSIZE) {
- case CS5:
- new_data = 5;
- break;
- case CS6:
- new_data = 6;
- break;
- case CS7:
- new_data = 7;
- break;
- case CS8:
- new_data = 8;
- break;
- default:
- /* cuz we always need a default ... */
- new_data = 5;
- break;
- }
- if (cflag & CSTOPB) {
- new_stop = 1;
- }
- if (cflag & PARENB) {
- new_parity_enable = 1;
- if (cflag & PARODD)
- new_parity = 1;
- }
- baud = uart_get_baud_rate(the_port, new_termios, old_termios,
- MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
- the_port->line));
-
- if (!the_port->fifosize)
- the_port->fifosize = FIFO_SIZE;
- uart_update_timeout(the_port, cflag, baud);
-
- the_port->ignore_status_mask = N_ALL_INPUT;
-
- state->port.low_latency = 1;
-
- if (iflag & IGNPAR)
- the_port->ignore_status_mask &= ~(N_PARITY_ERROR
- | N_FRAMING_ERROR);
- if (iflag & IGNBRK) {
- the_port->ignore_status_mask &= ~N_BREAK;
- if (iflag & IGNPAR)
- the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
- }
- if (!(cflag & CREAD)) {
- /* ignore everything */
- the_port->ignore_status_mask &= ~N_DATA_READY;
- }
-
- if (cflag & CRTSCTS) {
- /* enable hardware flow control */
- port->ip_sscr |= SSCR_HFC_EN;
- }
- else {
- /* disable hardware flow control */
- port->ip_sscr &= ~SSCR_HFC_EN;
- }
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
- /* Set the configuration and proper notification call */
- DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
- "config_port(baud %d data %d stop %d penable %d "
- " parity %d), notification 0x%x\n",
- __func__, (void *)port, the_port->line, cflag, baud,
- new_data, new_stop, new_parity_enable, new_parity,
- the_port->ignore_status_mask));
-
- if ((config_port(port, baud, /* baud */
- new_data, /* byte size */
- new_stop, /* stop bits */
- new_parity_enable, /* set parity */
- new_parity)) >= 0) { /* parity 1==odd */
- set_notification(port, the_port->ignore_status_mask, 1);
- }
-}
-
-/**
- * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic3_startup_local(struct uart_port *the_port)
-{
- struct ioc3_port *port;
-
- if (!the_port) {
- NOT_PROGRESS();
- return -1;
- }
-
- port = get_ioc3_port(the_port);
- if (!port) {
- NOT_PROGRESS();
- return -1;
- }
-
- local_open(port);
-
- /* set the protocol */
- ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
- PROTO_RS422);
- return 0;
-}
-
-/*
- * ioc3_cb_output_lowat - called when the output low water mark is hit
- * @port: port to output
- */
-static void ioc3_cb_output_lowat(struct ioc3_port *port)
-{
- unsigned long pflags;
-
- /* the_port->lock is set on the call here */
- if (port->ip_port) {
- spin_lock_irqsave(&port->ip_port->lock, pflags);
- transmit_chars(port->ip_port);
- spin_unlock_irqrestore(&port->ip_port->lock, pflags);
- }
-}
-
-/*
- * ioc3_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
- struct uart_icount *icount;
-
- icount = &the_port->icount;
-
- if (ncs & NCS_BREAK)
- icount->brk++;
- if (ncs & NCS_FRAMING)
- icount->frame++;
- if (ncs & NCS_OVERRUN)
- icount->overrun++;
- if (ncs & NCS_PARITY)
- icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port. Return the number of bytes
- * actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, char *buf, int len)
-{
- int prod_ptr, cons_ptr, total;
- struct ioc3_port *port = get_ioc3_port(the_port);
- struct ring *inring;
- struct ring_entry *entry;
- struct port_hooks *hooks;
- int byte_num;
- char *sc;
- int loop_counter;
-
- BUG_ON(!(len >= 0));
- BUG_ON(!port);
- hooks = port->ip_hooks;
-
- /* There is a nasty timing issue in the IOC3. When the rx_timer
- * expires or the rx_high condition arises, we take an interrupt.
- * At some point while servicing the interrupt, we read bytes from
- * the ring buffer and re-arm the rx_timer. However the rx_timer is
- * not started until the first byte is received *after* it is armed,
- * and any bytes pending in the rx construction buffers are not drained
- * to memory until either there are 4 bytes available or the rx_timer
- * expires. This leads to a potential situation where data is left
- * in the construction buffers forever - 1 to 3 bytes were received
- * after the interrupt was generated but before the rx_timer was
- * re-armed. At that point as long as no subsequent bytes are received
- * the timer will never be started and the bytes will remain in the
- * construction buffer forever. The solution is to execute a DRAIN
- * command after rearming the timer. This way any bytes received before
- * the DRAIN will be drained to memory, and any bytes received after
- * the DRAIN will start the TIMER and be drained when it expires.
- * Luckily, this only needs to be done when the DMA buffer is empty
- * since there is no requirement that this function return all
- * available data as long as it returns some.
- */
- /* Re-arm the timer */
-
- writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
-
- prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
- cons_ptr = port->ip_rx_cons;
-
- if (prod_ptr == cons_ptr) {
- int reset_dma = 0;
-
- /* Input buffer appears empty, do a flush. */
-
- /* DMA must be enabled for this to work. */
- if (!(port->ip_sscr & SSCR_DMA_EN)) {
- port->ip_sscr |= SSCR_DMA_EN;
- reset_dma = 1;
- }
-
- /* Potential race condition: we must reload the srpir after
- * issuing the drain command, otherwise we could think the rx
- * buffer is empty, then take a very long interrupt, and when
- * we come back it's full and we wait forever for the drain to
- * complete.
- */
- writel(port->ip_sscr | SSCR_RX_DRAIN,
- &port->ip_serial_regs->sscr);
- prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
-
- /* We must not wait for the DRAIN to complete unless there are
- * at least 8 bytes (2 ring entries) available to receive the
- * data otherwise the DRAIN will never complete and we'll
- * deadlock here.
- * In fact, to make things easier, I'll just ignore the flush if
- * there is any data at all now available.
- */
- if (prod_ptr == cons_ptr) {
- loop_counter = 0;
- while (readl(&port->ip_serial_regs->sscr) &
- SSCR_RX_DRAIN) {
- loop_counter++;
- if (loop_counter > MAXITER)
- return -1;
- }
-
- /* SIGH. We have to reload the prod_ptr *again* since
- * the drain may have caused it to change
- */
- prod_ptr = readl(&port->ip_serial_regs->srpir)
- & PROD_CONS_MASK;
- }
- if (reset_dma) {
- port->ip_sscr &= ~SSCR_DMA_EN;
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
- }
- inring = port->ip_inring;
- port->ip_flags &= ~READ_ABORTED;
-
- total = 0;
- loop_counter = 0xfffff; /* to avoid hangs */
-
- /* Grab bytes from the hardware */
- while ((prod_ptr != cons_ptr) && (len > 0)) {
- entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
-
- if (loop_counter-- <= 0) {
- printk(KERN_WARNING "IOC3 serial: "
- "possible hang condition/"
- "port stuck on read (line %d).\n",
- the_port->line);
- break;
- }
-
- /* According to the producer pointer, this ring entry
- * must contain some data. But if the PIO happened faster
- * than the DMA, the data may not be available yet, so let's
- * wait until it arrives.
- */
- if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
- /* Indicate the read is aborted so we don't disable
- * the interrupt thinking that the consumer is
- * congested.
- */
- port->ip_flags |= READ_ABORTED;
- len = 0;
- break;
- }
-
- /* Load the bytes/status out of the ring entry */
- for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
- sc = &(entry->ring_sc[byte_num]);
-
- /* Check for change in modem state or overrun */
- if ((*sc & RXSB_MODEM_VALID)
- && (port->ip_notify & N_DDCD)) {
- /* Notify upper layer if DCD dropped */
- if ((port->ip_flags & DCD_ON)
- && !(*sc & RXSB_DCD)) {
- /* If we have already copied some data,
- * return it. We'll pick up the carrier
- * drop on the next pass. That way we
- * don't throw away the data that has
- * already been copied back to
- * the caller's buffer.
- */
- if (total > 0) {
- len = 0;
- break;
- }
- port->ip_flags &= ~DCD_ON;
-
- /* Turn off this notification so the
- * carrier drop protocol won't see it
- * again when it does a read.
- */
- *sc &= ~RXSB_MODEM_VALID;
-
- /* To keep things consistent, we need
- * to update the consumer pointer so
- * the next reader won't come in and
- * try to read the same ring entries
- * again. This must be done here before
- * the dcd change.
- */
-
- if ((entry->ring_allsc & RING_ANY_VALID)
- == 0) {
- cons_ptr += (int)sizeof
- (struct ring_entry);
- cons_ptr &= PROD_CONS_MASK;
- }
- writel(cons_ptr,
- &port->ip_serial_regs->srcir);
- port->ip_rx_cons = cons_ptr;
-
- /* Notify upper layer of carrier drop */
- if ((port->ip_notify & N_DDCD)
- && port->ip_port) {
- uart_handle_dcd_change
- (port->ip_port, 0);
- wake_up_interruptible
- (&the_port->state->
- port.delta_msr_wait);
- }
-
- /* If we had any data to return, we
- * would have returned it above.
- */
- return 0;
- }
- }
- if (*sc & RXSB_MODEM_VALID) {
- /* Notify that an input overrun occurred */
- if ((*sc & RXSB_OVERRUN)
- && (port->ip_notify & N_OVERRUN_ERROR)) {
- ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
- }
- /* Don't look at this byte again */
- *sc &= ~RXSB_MODEM_VALID;
- }
-
- /* Check for valid data or RX errors */
- if ((*sc & RXSB_DATA_VALID) &&
- ((*sc & (RXSB_PAR_ERR
- | RXSB_FRAME_ERR | RXSB_BREAK))
- && (port->ip_notify & (N_PARITY_ERROR
- | N_FRAMING_ERROR
- | N_BREAK)))) {
- /* There is an error condition on the next byte.
- * If we have already transferred some bytes,
- * we'll stop here. Otherwise if this is the
- * first byte to be read, we'll just transfer
- * it alone after notifying the
- * upper layer of its status.
- */
- if (total > 0) {
- len = 0;
- break;
- } else {
- if ((*sc & RXSB_PAR_ERR) &&
- (port->
- ip_notify & N_PARITY_ERROR)) {
- ioc3_cb_post_ncs(the_port,
- NCS_PARITY);
- }
- if ((*sc & RXSB_FRAME_ERR) &&
- (port->
- ip_notify & N_FRAMING_ERROR)) {
- ioc3_cb_post_ncs(the_port,
- NCS_FRAMING);
- }
- if ((*sc & RXSB_BREAK)
- && (port->ip_notify & N_BREAK)) {
- ioc3_cb_post_ncs
- (the_port, NCS_BREAK);
- }
- len = 1;
- }
- }
- if (*sc & RXSB_DATA_VALID) {
- *sc &= ~RXSB_DATA_VALID;
- *buf = entry->ring_data[byte_num];
- buf++;
- len--;
- total++;
- }
- }
-
- /* If we used up this entry entirely, go on to the next one,
- * otherwise we must have run out of buffer space, so
- * leave the consumer pointer here for the next read in case
- * there are still unread bytes in this entry.
- */
- if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
- cons_ptr += (int)sizeof(struct ring_entry);
- cons_ptr &= PROD_CONS_MASK;
- }
- }
-
- /* Update consumer pointer and re-arm rx timer interrupt */
- writel(cons_ptr, &port->ip_serial_regs->srcir);
- port->ip_rx_cons = cons_ptr;
-
- /* If we have now dipped below the rx high water mark and we have
- * rx_high interrupt turned off, we can now turn it back on again.
- */
- if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
- & PROD_CONS_MASK) <
- ((port->
- ip_sscr &
- SSCR_RX_THRESHOLD)
- << PROD_CONS_PTR_OFF))) {
- port->ip_flags &= ~INPUT_HIGH;
- enable_intrs(port, hooks->intr_rx_high);
- }
- return total;
-}
-
-/**
- * receive_chars - upper level read.
- * @the_port: port to read from
- */
-static int receive_chars(struct uart_port *the_port)
-{
- unsigned char ch[MAX_CHARS];
- int read_count = 0, read_room, flip = 0;
- struct uart_state *state = the_port->state;
- struct ioc3_port *port = get_ioc3_port(the_port);
- unsigned long pflags;
-
- /* Make sure all the pointers are "good" ones */
- if (!state)
- return 0;
-
- if (!(port->ip_flags & INPUT_ENABLE))
- return 0;
-
- spin_lock_irqsave(&the_port->lock, pflags);
-
- read_count = do_read(the_port, ch, MAX_CHARS);
- if (read_count > 0) {
- flip = 1;
- read_room = tty_insert_flip_string(&state->port, ch,
- read_count);
- the_port->icount.rx += read_count;
- }
- spin_unlock_irqrestore(&the_port->lock, pflags);
-
- if (flip)
- tty_flip_buffer_push(&state->port);
-
- return read_count;
-}
-
-/**
- * ioc3uart_intr_one - lowest level (per port) interrupt handler.
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- */
-
-static inline int
-ioc3uart_intr_one(struct ioc3_submodule *is,
- struct ioc3_driver_data *idd,
- unsigned int pending)
-{
- int port_num = GET_PORT_FROM_SIO_IR(pending);
- struct port_hooks *hooks;
- unsigned int rx_high_rd_aborted = 0;
- unsigned long flags;
- struct uart_port *the_port;
- struct ioc3_port *port;
- int loop_counter;
- struct ioc3_card *card_ptr;
- unsigned int sio_ir;
-
- card_ptr = idd->data[is->id];
- port = card_ptr->ic_port[port_num].icp_port;
- hooks = port->ip_hooks;
-
- /* Possible race condition here: The tx_mt interrupt bit may be
- * cleared without the intervention of the interrupt handler,
- * e.g. by a write. If the top level interrupt handler reads a
- * tx_mt, then some other processor does a write, starting up
- * output, then we come in here, see the tx_mt and stop DMA, the
- * output started by the other processor will hang. Thus we can
- * only rely on tx_mt being legitimate if it is read while the
- * port lock is held. Therefore this bit must be ignored in the
- * passed in interrupt mask which was read by the top level
- * interrupt handler since the port lock was not held at the time
- * it was read. We can only rely on this bit being accurate if it
- * is read while the port lock is held. So we'll clear it for now,
- * and reload it later once we have the port lock.
- */
-
- sio_ir = pending & ~(hooks->intr_tx_mt);
- spin_lock_irqsave(&port->ip_lock, flags);
-
- loop_counter = MAXITER; /* to avoid hangs */
-
- do {
- uint32_t shadow;
-
- if (loop_counter-- <= 0) {
- printk(KERN_WARNING "IOC3 serial: "
- "possible hang condition/"
- "port stuck on interrupt (line %d).\n",
- ((struct uart_port *)port->ip_port)->line);
- break;
- }
- /* Handle a DCD change */
- if (sio_ir & hooks->intr_delta_dcd) {
- ioc3_ack(is, idd, hooks->intr_delta_dcd);
- shadow = readl(&port->ip_serial_regs->shadow);
-
- if ((port->ip_notify & N_DDCD)
- && (shadow & SHADOW_DCD)
- && (port->ip_port)) {
- the_port = port->ip_port;
- uart_handle_dcd_change(the_port,
- shadow & SHADOW_DCD);
- wake_up_interruptible
- (&the_port->state->port.delta_msr_wait);
- } else if ((port->ip_notify & N_DDCD)
- && !(shadow & SHADOW_DCD)) {
- /* Flag delta DCD/no DCD */
- uart_handle_dcd_change(port->ip_port,
- shadow & SHADOW_DCD);
- port->ip_flags |= DCD_ON;
- }
- }
-
- /* Handle a CTS change */
- if (sio_ir & hooks->intr_delta_cts) {
- ioc3_ack(is, idd, hooks->intr_delta_cts);
- shadow = readl(&port->ip_serial_regs->shadow);
-
- if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
- the_port = port->ip_port;
- uart_handle_cts_change(the_port, shadow
- & SHADOW_CTS);
- wake_up_interruptible
- (&the_port->state->port.delta_msr_wait);
- }
- }
-
- /* rx timeout interrupt. Must be some data available. Put this
- * before the check for rx_high since servicing this condition
- * may cause that condition to clear.
- */
- if (sio_ir & hooks->intr_rx_timer) {
- ioc3_ack(is, idd, hooks->intr_rx_timer);
- if ((port->ip_notify & N_DATA_READY)
- && (port->ip_port)) {
- receive_chars(port->ip_port);
- }
- }
-
- /* rx high interrupt. Must be after rx_timer. */
- else if (sio_ir & hooks->intr_rx_high) {
- /* Data available, notify upper layer */
- if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
- receive_chars(port->ip_port);
- }
-
- /* We can't ACK this interrupt. If receive_chars didn't
- * cause the condition to clear, we'll have to disable
- * the interrupt until the data is drained.
- * If the read was aborted, don't disable the interrupt
- * as this may cause us to hang indefinitely. An
- * aborted read generally means that this interrupt
- * hasn't been delivered to the cpu yet anyway, even
- * though we see it as asserted when we read the sio_ir.
- */
- if ((sio_ir = PENDING(card_ptr, idd))
- & hooks->intr_rx_high) {
- if (port->ip_flags & READ_ABORTED) {
- rx_high_rd_aborted++;
- }
- else {
- card_ptr->ic_enable &= ~hooks->intr_rx_high;
- port->ip_flags |= INPUT_HIGH;
- }
- }
- }
-
- /* We got a low water interrupt: notify upper layer to
- * send more data. Must come before tx_mt since servicing
- * this condition may cause that condition to clear.
- */
- if (sio_ir & hooks->intr_tx_explicit) {
- port->ip_flags &= ~LOWAT_WRITTEN;
- ioc3_ack(is, idd, hooks->intr_tx_explicit);
- if (port->ip_notify & N_OUTPUT_LOWAT)
- ioc3_cb_output_lowat(port);
- }
-
- /* Handle tx_mt. Must come after tx_explicit. */
- else if (sio_ir & hooks->intr_tx_mt) {
- /* If we are expecting a lowat notification
- * and we get to this point it probably means that for
- * some reason the tx_explicit didn't work as expected
- * (that can legitimately happen if the output buffer is
- * filled up in just the right way).
- * So send the notification now.
- */
- if (port->ip_notify & N_OUTPUT_LOWAT) {
- ioc3_cb_output_lowat(port);
-
- /* We need to reload the sio_ir since the lowat
- * call may have caused another write to occur,
- * clearing the tx_mt condition.
- */
- sio_ir = PENDING(card_ptr, idd);
- }
-
- /* If the tx_mt condition still persists even after the
- * lowat call, we've got some work to do.
- */
- if (sio_ir & hooks->intr_tx_mt) {
- /* If we are not currently expecting DMA input,
- * and the transmitter has just gone idle,
- * there is no longer any reason for DMA, so
- * disable it.
- */
- if (!(port->ip_notify
- & (N_DATA_READY | N_DDCD))) {
- BUG_ON(!(port->ip_sscr
- & SSCR_DMA_EN));
- port->ip_sscr &= ~SSCR_DMA_EN;
- writel(port->ip_sscr,
- &port->ip_serial_regs->sscr);
- }
- /* Prevent infinite tx_mt interrupt */
- card_ptr->ic_enable &= ~hooks->intr_tx_mt;
- }
- }
- sio_ir = PENDING(card_ptr, idd);
-
- /* if the read was aborted and only hooks->intr_rx_high,
- * clear hooks->intr_rx_high, so we do not loop forever.
- */
-
- if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
- sio_ir &= ~hooks->intr_rx_high;
- }
- } while (sio_ir & hooks->intr_all);
-
- spin_unlock_irqrestore(&port->ip_lock, flags);
- ioc3_enable(is, idd, card_ptr->ic_enable);
- return 0;
-}
-
-/**
- * ioc3uart_intr - field all serial interrupts
- * @is : submodule
- * @idd: driver data
- * @pending: interrupts to handle
- *
- */
-
-static int ioc3uart_intr(struct ioc3_submodule *is,
- struct ioc3_driver_data *idd,
- unsigned int pending)
-{
- int ret = 0;
-
- /*
- * The upper level interrupt handler sends interrupts for both ports
- * here. So we need to call for each port with its interrupts.
- */
-
- if (pending & SIO_IR_SA)
- ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
- if (pending & SIO_IR_SB)
- ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
-
- return ret;
-}
-
-/**
- * ic3_type
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic3_type(struct uart_port *the_port)
-{
- if (IS_RS232(the_port->line))
- return "SGI IOC3 Serial [rs232]";
- else
- return "SGI IOC3 Serial [rs422]";
-}
-
-/**
- * ic3_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic3_tx_empty(struct uart_port *the_port)
-{
- unsigned int ret = 0;
- struct ioc3_port *port = get_ioc3_port(the_port);
-
- if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
- ret = TIOCSER_TEMT;
- return ret;
-}
-
-/**
- * ic3_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic3_stop_tx(struct uart_port *the_port)
-{
- struct ioc3_port *port = get_ioc3_port(the_port);
-
- if (port)
- set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * ic3_stop_rx - stop the receiver
- * @port: Port to operate on
- *
- */
-static void ic3_stop_rx(struct uart_port *the_port)
-{
- struct ioc3_port *port = get_ioc3_port(the_port);
-
- if (port)
- port->ip_flags &= ~INPUT_ENABLE;
-}
-
-/**
- * null_void_function
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic3_shutdown - shut down the port - free irq and disable
- * @port: port to shut down
- *
- */
-static void ic3_shutdown(struct uart_port *the_port)
-{
- unsigned long port_flags;
- struct ioc3_port *port;
- struct uart_state *state;
-
- port = get_ioc3_port(the_port);
- if (!port)
- return;
-
- state = the_port->state;
- wake_up_interruptible(&state->port.delta_msr_wait);
-
- spin_lock_irqsave(&the_port->lock, port_flags);
- set_notification(port, N_ALL, 0);
- spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
- unsigned char mcr = 0;
-
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
-
- set_mcr(the_port, mcr, SHADOW_DTR);
-}
-
-/**
- * ic3_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic3_get_mctrl(struct uart_port *the_port)
-{
- struct ioc3_port *port = get_ioc3_port(the_port);
- uint32_t shadow;
- unsigned int ret = 0;
-
- if (!port)
- return 0;
-
- shadow = readl(&port->ip_serial_regs->shadow);
- if (shadow & SHADOW_DCD)
- ret |= TIOCM_CD;
- if (shadow & SHADOW_DR)
- ret |= TIOCM_DSR;
- if (shadow & SHADOW_CTS)
- ret |= TIOCM_CTS;
- return ret;
-}
-
-/**
- * ic3_start_tx - Start transmitter. Called with the_port->lock
- * @port: Port to operate on
- *
- */
-static void ic3_start_tx(struct uart_port *the_port)
-{
- struct ioc3_port *port = get_ioc3_port(the_port);
-
- if (port) {
- set_notification(port, N_OUTPUT_LOWAT, 1);
- enable_intrs(port, port->ip_hooks->intr_tx_mt);
- }
-}
-
-/**
- * ic3_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic3_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic3_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int ic3_startup(struct uart_port *the_port)
-{
- int retval;
- struct ioc3_port *port;
- struct ioc3_card *card_ptr;
- unsigned long port_flags;
-
- if (!the_port) {
- NOT_PROGRESS();
- return -ENODEV;
- }
- port = get_ioc3_port(the_port);
- if (!port) {
- NOT_PROGRESS();
- return -ENODEV;
- }
- card_ptr = port->ip_card;
- port->ip_port = the_port;
-
- if (!card_ptr) {
- NOT_PROGRESS();
- return -ENODEV;
- }
-
- /* Start up the serial port */
- spin_lock_irqsave(&the_port->lock, port_flags);
- retval = ic3_startup_local(the_port);
- spin_unlock_irqrestore(&the_port->lock, port_flags);
- return retval;
-}
-
-/**
- * ic3_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic3_set_termios(struct uart_port *the_port,
- struct ktermios *termios, struct ktermios *old_termios)
-{
- unsigned long port_flags;
-
- spin_lock_irqsave(&the_port->lock, port_flags);
- ioc3_change_speed(the_port, termios, old_termios);
- spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic3_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic3_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-static const struct uart_ops ioc3_ops = {
- .tx_empty = ic3_tx_empty,
- .set_mctrl = ic3_set_mctrl,
- .get_mctrl = ic3_get_mctrl,
- .stop_tx = ic3_stop_tx,
- .start_tx = ic3_start_tx,
- .stop_rx = ic3_stop_rx,
- .break_ctl = ic3_break_ctl,
- .startup = ic3_startup,
- .shutdown = ic3_shutdown,
- .set_termios = ic3_set_termios,
- .type = ic3_type,
- .release_port = null_void_function,
- .request_port = ic3_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc3_uart = {
- .owner = THIS_MODULE,
- .driver_name = "ioc3_serial",
- .dev_name = DEVICE_NAME,
- .major = DEVICE_MAJOR,
- .minor = DEVICE_MINOR,
- .nr = MAX_LOGICAL_PORTS
-};
-
-/**
- * ioc3_serial_core_attach - register with serial core
- * This is done during pci probing
- * @is: submodule struct for this
- * @idd: handle for this card
- */
-static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
- struct ioc3_driver_data *idd)
-{
- struct ioc3_port *port;
- struct uart_port *the_port;
- struct ioc3_card *card_ptr = idd->data[is->id];
- int ii, phys_port;
- struct pci_dev *pdev = idd->pdev;
-
- DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
- __func__, pdev, (void *)card_ptr));
-
- if (!card_ptr)
- return -ENODEV;
-
- /* once around for each logical port on this card */
- for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
- phys_port = GET_PHYSICAL_PORT(ii);
- the_port = &card_ptr->ic_port[phys_port].
- icp_uart_port[GET_LOGICAL_PORT(ii)];
- port = card_ptr->ic_port[phys_port].icp_port;
- port->ip_port = the_port;
-
- DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
- __func__, (void *)the_port, (void *)port,
- phys_port, ii));
-
- /* membase, iobase and mapbase just need to be non-0 */
- the_port->membase = (unsigned char __iomem *)1;
- the_port->iobase = (pdev->bus->number << 16) | ii;
- the_port->line = (Num_of_ioc3_cards << 2) | ii;
- the_port->mapbase = 1;
- the_port->type = PORT_16550A;
- the_port->fifosize = FIFO_SIZE;
- the_port->ops = &ioc3_ops;
- the_port->irq = idd->irq_io;
- the_port->dev = &pdev->dev;
-
- if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
- printk(KERN_WARNING
- "%s: unable to add port %d bus %d\n",
- __func__, the_port->line, pdev->bus->number);
- } else {
- DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
- the_port->line, the_port->irq, pdev->bus->number));
- }
-
- /* all ports are rs232 for now */
- if (IS_PHYSICAL_PORT(ii))
- ioc3_set_proto(port, PROTO_RS232);
- }
- return 0;
-}
-
-/**
- * ioc3uart_remove - register detach function
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this submodule
- */
-
-static int ioc3uart_remove(struct ioc3_submodule *is,
- struct ioc3_driver_data *idd)
-{
- struct ioc3_card *card_ptr = idd->data[is->id];
- struct uart_port *the_port;
- struct ioc3_port *port;
- int ii;
-
- if (card_ptr) {
- for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
- the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
- icp_uart_port[GET_LOGICAL_PORT(ii)];
- if (the_port)
- uart_remove_one_port(&ioc3_uart, the_port);
- port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
- if (port && IS_PHYSICAL_PORT(ii)
- && (GET_PHYSICAL_PORT(ii) == 0)) {
- pci_free_consistent(port->ip_idd->pdev,
- TOTAL_RING_BUF_SIZE,
- (void *)port->ip_cpu_ringbuf,
- port->ip_dma_ringbuf);
- kfree(port);
- card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
- icp_port = NULL;
- }
- }
- kfree(card_ptr);
- idd->data[is->id] = NULL;
- }
- return 0;
-}
-
-/**
- * ioc3uart_probe - card probe function called from shim driver
- * @is: submodule struct for this submodule
- * @idd: ioc3 driver data for this card
- */
-
-static int
-ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
-{
- struct pci_dev *pdev = idd->pdev;
- struct ioc3_card *card_ptr;
- int ret = 0;
- struct ioc3_port *port;
- struct ioc3_port *ports[PORTS_PER_CARD];
- int phys_port;
- int cnt;
-
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
-
- card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
- if (!card_ptr) {
- printk(KERN_WARNING "ioc3_attach_one"
- ": unable to get memory for the IOC3\n");
- return -ENOMEM;
- }
- idd->data[is->id] = card_ptr;
- Submodule_slot = is->id;
-
- writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
- ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
- (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
-
- pci_write_config_dword(pdev, PCI_LAT, 0xff00);
-
- /* Enable serial port mode select generic PIO pins as outputs */
- ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
-
- /* Create port structures for each port */
- for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
- port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL);
- if (!port) {
- printk(KERN_WARNING
- "IOC3 serial memory not available for port\n");
- ret = -ENOMEM;
- goto out4;
- }
- spin_lock_init(&port->ip_lock);
-
- /* we need to remember the previous ones, to point back to
- * them farther down - setting up the ring buffers.
- */
- ports[phys_port] = port;
-
- /* init to something useful */
- card_ptr->ic_port[phys_port].icp_port = port;
- port->ip_is = is;
- port->ip_idd = idd;
- port->ip_baud = 9600;
- port->ip_card = card_ptr;
- port->ip_hooks = &hooks_array[phys_port];
-
- /* Setup each port */
- if (phys_port == 0) {
- port->ip_serial_regs = &idd->vma->port_a;
- port->ip_uart_regs = &idd->vma->sregs.uarta;
-
- DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
- "ip_uart_regs 0x%p\n",
- __func__,
- (void *)port->ip_serial_regs,
- (void *)port->ip_uart_regs));
-
- /* setup ring buffers */
- port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
- TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
-
- BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
- (TOTAL_RING_BUF_SIZE - 1)) == 0));
- port->ip_inring = RING(port, RX_A);
- port->ip_outring = RING(port, TX_A);
- DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
- "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
- "ip_outring 0x%p\n",
- __func__,
- (void *)port->ip_cpu_ringbuf,
- (void *)port->ip_dma_ringbuf,
- (void *)port->ip_inring,
- (void *)port->ip_outring));
- }
- else {
- port->ip_serial_regs = &idd->vma->port_b;
- port->ip_uart_regs = &idd->vma->sregs.uartb;
-
- DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
- "ip_uart_regs 0x%p\n",
- __func__,
- (void *)port->ip_serial_regs,
- (void *)port->ip_uart_regs));
-
- /* share the ring buffers */
- port->ip_dma_ringbuf =
- ports[phys_port - 1]->ip_dma_ringbuf;
- port->ip_cpu_ringbuf =
- ports[phys_port - 1]->ip_cpu_ringbuf;
- port->ip_inring = RING(port, RX_B);
- port->ip_outring = RING(port, TX_B);
- DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
- "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
- "ip_outring 0x%p\n",
- __func__,
- (void *)port->ip_cpu_ringbuf,
- (void *)port->ip_dma_ringbuf,
- (void *)port->ip_inring,
- (void *)port->ip_outring));
- }
-
- DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
- __func__,
- phys_port, (void *)port, (void *)card_ptr));
- DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
- (void *)port->ip_serial_regs,
- (void *)port->ip_uart_regs));
-
- /* Initialize the hardware for IOC3 */
- port_init(port);
-
- DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
- "outring 0x%p\n",
- __func__,
- phys_port, (void *)port,
- (void *)port->ip_inring,
- (void *)port->ip_outring));
-
- }
-
- /* register port with the serial core */
-
- ret = ioc3_serial_core_attach(is, idd);
- if (ret)
- goto out4;
-
- Num_of_ioc3_cards++;
-
- return ret;
-
- /* error exits that give back resources */
-out4:
- for (cnt = 0; cnt < phys_port; cnt++)
- kfree(ports[cnt]);
-
- kfree(card_ptr);
- return ret;
-}
-
-static struct ioc3_submodule ioc3uart_ops = {
- .name = "IOC3uart",
- .probe = ioc3uart_probe,
- .remove = ioc3uart_remove,
- /* call .intr for both ports initially */
- .irq_mask = SIO_IR_SA | SIO_IR_SB,
- .intr = ioc3uart_intr,
- .owner = THIS_MODULE,
-};
-
-/**
- * ioc3_detect - module init called,
- */
-static int __init ioc3uart_init(void)
-{
- int ret;
-
- /* register with serial core */
- if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
- printk(KERN_WARNING
- "%s: Couldn't register IOC3 uart serial driver\n",
- __func__);
- return ret;
- }
- ret = ioc3_register_submodule(&ioc3uart_ops);
- if (ret)
- uart_unregister_driver(&ioc3_uart);
- return ret;
-}
-
-static void __exit ioc3uart_exit(void)
-{
- ioc3_unregister_submodule(&ioc3uart_ops);
- uart_unregister_driver(&ioc3_uart);
-}
-
-module_init(ioc3uart_init);
-module_exit(ioc3uart_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
deleted file mode 100644
index db5b979e5a0c..000000000000
--- a/drivers/tty/serial/ioc4_serial.c
+++ /dev/null
@@ -1,2955 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2003-2006 Silicon Graphics, Inc. All Rights Reserved.
- */
-
-
-/*
- * This file contains a module version of the ioc4 serial driver. This
- * includes all the support functions needed (support functions, etc.)
- * and the serial driver itself.
- */
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ioc4.h>
-#include <linux/serial_core.h>
-#include <linux/slab.h>
-
-/*
- * interesting things about the ioc4
- */
-
-#define IOC4_NUM_SERIAL_PORTS 4 /* max ports per card */
-#define IOC4_NUM_CARDS 8 /* max cards per partition */
-
-#define GET_SIO_IR(_n) (_n == 0) ? (IOC4_SIO_IR_S0) : \
- (_n == 1) ? (IOC4_SIO_IR_S1) : \
- (_n == 2) ? (IOC4_SIO_IR_S2) : \
- (IOC4_SIO_IR_S3)
-
-#define GET_OTHER_IR(_n) (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \
- (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \
- (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \
- (IOC4_OTHER_IR_S3_MEMERR)
-
-
-/*
- * All IOC4 registers are 32 bits wide.
- */
-
-/*
- * PCI Memory Space Map
- */
-#define IOC4_PCI_ERR_ADDR_L 0x000 /* Low Error Address */
-#define IOC4_PCI_ERR_ADDR_VLD (0x1 << 0)
-#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1)
-#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK (0xe << 1)
-#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK (0x1 << 1)
-#define IOC4_PCI_ERR_ADDR_MUL_ERR (0x1 << 5)
-#define IOC4_PCI_ERR_ADDR_ADDR_MSK (0x3ffffff << 6)
-
-/* Interrupt types */
-#define IOC4_SIO_INTR_TYPE 0
-#define IOC4_OTHER_INTR_TYPE 1
-#define IOC4_NUM_INTR_TYPES 2
-
-/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES */
-#define IOC4_SIO_IR_S0_TX_MT 0x00000001 /* Serial port 0 TX empty */
-#define IOC4_SIO_IR_S0_RX_FULL 0x00000002 /* Port 0 RX buf full */
-#define IOC4_SIO_IR_S0_RX_HIGH 0x00000004 /* Port 0 RX hiwat */
-#define IOC4_SIO_IR_S0_RX_TIMER 0x00000008 /* Port 0 RX timeout */
-#define IOC4_SIO_IR_S0_DELTA_DCD 0x00000010 /* Port 0 delta DCD */
-#define IOC4_SIO_IR_S0_DELTA_CTS 0x00000020 /* Port 0 delta CTS */
-#define IOC4_SIO_IR_S0_INT 0x00000040 /* Port 0 pass-thru intr */
-#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080 /* Port 0 explicit TX thru */
-#define IOC4_SIO_IR_S1_TX_MT 0x00000100 /* Serial port 1 */
-#define IOC4_SIO_IR_S1_RX_FULL 0x00000200 /* */
-#define IOC4_SIO_IR_S1_RX_HIGH 0x00000400 /* */
-#define IOC4_SIO_IR_S1_RX_TIMER 0x00000800 /* */
-#define IOC4_SIO_IR_S1_DELTA_DCD 0x00001000 /* */
-#define IOC4_SIO_IR_S1_DELTA_CTS 0x00002000 /* */
-#define IOC4_SIO_IR_S1_INT 0x00004000 /* */
-#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000 /* */
-#define IOC4_SIO_IR_S2_TX_MT 0x00010000 /* Serial port 2 */
-#define IOC4_SIO_IR_S2_RX_FULL 0x00020000 /* */
-#define IOC4_SIO_IR_S2_RX_HIGH 0x00040000 /* */
-#define IOC4_SIO_IR_S2_RX_TIMER 0x00080000 /* */
-#define IOC4_SIO_IR_S2_DELTA_DCD 0x00100000 /* */
-#define IOC4_SIO_IR_S2_DELTA_CTS 0x00200000 /* */
-#define IOC4_SIO_IR_S2_INT 0x00400000 /* */
-#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000 /* */
-#define IOC4_SIO_IR_S3_TX_MT 0x01000000 /* Serial port 3 */
-#define IOC4_SIO_IR_S3_RX_FULL 0x02000000 /* */
-#define IOC4_SIO_IR_S3_RX_HIGH 0x04000000 /* */
-#define IOC4_SIO_IR_S3_RX_TIMER 0x08000000 /* */
-#define IOC4_SIO_IR_S3_DELTA_DCD 0x10000000 /* */
-#define IOC4_SIO_IR_S3_DELTA_CTS 0x20000000 /* */
-#define IOC4_SIO_IR_S3_INT 0x40000000 /* */
-#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000 /* */
-
-/* Per device interrupt masks */
-#define IOC4_SIO_IR_S0 (IOC4_SIO_IR_S0_TX_MT | \
- IOC4_SIO_IR_S0_RX_FULL | \
- IOC4_SIO_IR_S0_RX_HIGH | \
- IOC4_SIO_IR_S0_RX_TIMER | \
- IOC4_SIO_IR_S0_DELTA_DCD | \
- IOC4_SIO_IR_S0_DELTA_CTS | \
- IOC4_SIO_IR_S0_INT | \
- IOC4_SIO_IR_S0_TX_EXPLICIT)
-#define IOC4_SIO_IR_S1 (IOC4_SIO_IR_S1_TX_MT | \
- IOC4_SIO_IR_S1_RX_FULL | \
- IOC4_SIO_IR_S1_RX_HIGH | \
- IOC4_SIO_IR_S1_RX_TIMER | \
- IOC4_SIO_IR_S1_DELTA_DCD | \
- IOC4_SIO_IR_S1_DELTA_CTS | \
- IOC4_SIO_IR_S1_INT | \
- IOC4_SIO_IR_S1_TX_EXPLICIT)
-#define IOC4_SIO_IR_S2 (IOC4_SIO_IR_S2_TX_MT | \
- IOC4_SIO_IR_S2_RX_FULL | \
- IOC4_SIO_IR_S2_RX_HIGH | \
- IOC4_SIO_IR_S2_RX_TIMER | \
- IOC4_SIO_IR_S2_DELTA_DCD | \
- IOC4_SIO_IR_S2_DELTA_CTS | \
- IOC4_SIO_IR_S2_INT | \
- IOC4_SIO_IR_S2_TX_EXPLICIT)
-#define IOC4_SIO_IR_S3 (IOC4_SIO_IR_S3_TX_MT | \
- IOC4_SIO_IR_S3_RX_FULL | \
- IOC4_SIO_IR_S3_RX_HIGH | \
- IOC4_SIO_IR_S3_RX_TIMER | \
- IOC4_SIO_IR_S3_DELTA_DCD | \
- IOC4_SIO_IR_S3_DELTA_CTS | \
- IOC4_SIO_IR_S3_INT | \
- IOC4_SIO_IR_S3_TX_EXPLICIT)
-
-/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */
-#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */
-#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */
-#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */
-#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */
-#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */
-#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */
-#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */
-#define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */
-#define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */
-#define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */
-
-#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \
- IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)
-
-/* Bitmasks for IOC4_SIO_CR */
-#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */
-#define IOC4_SIO_CR_ARB_DIAG_TX0 0x00000000
-#define IOC4_SIO_CR_ARB_DIAG_RX0 0x00000010
-#define IOC4_SIO_CR_ARB_DIAG_TX1 0x00000020
-#define IOC4_SIO_CR_ARB_DIAG_RX1 0x00000030
-#define IOC4_SIO_CR_ARB_DIAG_TX2 0x00000040
-#define IOC4_SIO_CR_ARB_DIAG_RX2 0x00000050
-#define IOC4_SIO_CR_ARB_DIAG_TX3 0x00000060
-#define IOC4_SIO_CR_ARB_DIAG_RX3 0x00000070
-#define IOC4_SIO_CR_SIO_DIAG_IDLE 0x00000080 /* 0 -> active request among
- serial ports (ro) */
-/* Defs for some of the generic I/O pins */
-#define IOC4_GPCR_UART0_MODESEL 0x10 /* Pin is output to port 0
- mode sel */
-#define IOC4_GPCR_UART1_MODESEL 0x20 /* Pin is output to port 1
- mode sel */
-#define IOC4_GPCR_UART2_MODESEL 0x40 /* Pin is output to port 2
- mode sel */
-#define IOC4_GPCR_UART3_MODESEL 0x80 /* Pin is output to port 3
- mode sel */
-
-#define IOC4_GPPR_UART0_MODESEL_PIN 4 /* GIO pin controlling
- uart 0 mode select */
-#define IOC4_GPPR_UART1_MODESEL_PIN 5 /* GIO pin controlling
- uart 1 mode select */
-#define IOC4_GPPR_UART2_MODESEL_PIN 6 /* GIO pin controlling
- uart 2 mode select */
-#define IOC4_GPPR_UART3_MODESEL_PIN 7 /* GIO pin controlling
- uart 3 mode select */
-
-/* Bitmasks for serial RX status byte */
-#define IOC4_RXSB_OVERRUN 0x01 /* Char(s) lost */
-#define IOC4_RXSB_PAR_ERR 0x02 /* Parity error */
-#define IOC4_RXSB_FRAME_ERR 0x04 /* Framing error */
-#define IOC4_RXSB_BREAK 0x08 /* Break character */
-#define IOC4_RXSB_CTS 0x10 /* State of CTS */
-#define IOC4_RXSB_DCD 0x20 /* State of DCD */
-#define IOC4_RXSB_MODEM_VALID 0x40 /* DCD, CTS, and OVERRUN are valid */
-#define IOC4_RXSB_DATA_VALID 0x80 /* Data byte, FRAME_ERR PAR_ERR
- * & BREAK valid */
-
-/* Bitmasks for serial TX control byte */
-#define IOC4_TXCB_INT_WHEN_DONE 0x20 /* Interrupt after this byte is sent */
-#define IOC4_TXCB_INVALID 0x00 /* Byte is invalid */
-#define IOC4_TXCB_VALID 0x40 /* Byte is valid */
-#define IOC4_TXCB_MCR 0x80 /* Data<7:0> to modem control reg */
-#define IOC4_TXCB_DELAY 0xc0 /* Delay data<7:0> mSec */
-
-/* Bitmasks for IOC4_SBBR_L */
-#define IOC4_SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */
-
-/* Bitmasks for IOC4_SSCR_<3:0> */
-#define IOC4_SSCR_RX_THRESHOLD 0x000001ff /* Hiwater mark */
-#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */
-#define IOC4_SSCR_HFC_EN 0x00020000 /* Hardware flow control enabled */
-#define IOC4_SSCR_RX_RING_DCD 0x00040000 /* Post RX record on delta-DCD */
-#define IOC4_SSCR_RX_RING_CTS 0x00080000 /* Post RX record on delta-CTS */
-#define IOC4_SSCR_DIAG 0x00200000 /* Bypass clock divider for sim */
-#define IOC4_SSCR_RX_DRAIN 0x08000000 /* Drain RX buffer to memory */
-#define IOC4_SSCR_DMA_EN 0x10000000 /* Enable ring buffer DMA */
-#define IOC4_SSCR_DMA_PAUSE 0x20000000 /* Pause DMA */
-#define IOC4_SSCR_PAUSE_STATE 0x40000000 /* Sets when PAUSE takes effect */
-#define IOC4_SSCR_RESET 0x80000000 /* Reset DMA channels */
-
-/* All producer/consumer pointers are the same bitfield */
-#define IOC4_PROD_CONS_PTR_4K 0x00000ff8 /* For 4K buffers */
-#define IOC4_PROD_CONS_PTR_1K 0x000003f8 /* For 1K buffers */
-#define IOC4_PROD_CONS_PTR_OFF 3
-
-/* Bitmasks for IOC4_SRCIR_<3:0> */
-#define IOC4_SRCIR_ARM 0x80000000 /* Arm RX timer */
-
-/* Bitmasks for IOC4_SHADOW_<3:0> */
-#define IOC4_SHADOW_DR 0x00000001 /* Data ready */
-#define IOC4_SHADOW_OE 0x00000002 /* Overrun error */
-#define IOC4_SHADOW_PE 0x00000004 /* Parity error */
-#define IOC4_SHADOW_FE 0x00000008 /* Framing error */
-#define IOC4_SHADOW_BI 0x00000010 /* Break interrupt */
-#define IOC4_SHADOW_THRE 0x00000020 /* Xmit holding register empty */
-#define IOC4_SHADOW_TEMT 0x00000040 /* Xmit shift register empty */
-#define IOC4_SHADOW_RFCE 0x00000080 /* Char in RX fifo has an error */
-#define IOC4_SHADOW_DCTS 0x00010000 /* Delta clear to send */
-#define IOC4_SHADOW_DDCD 0x00080000 /* Delta data carrier detect */
-#define IOC4_SHADOW_CTS 0x00100000 /* Clear to send */
-#define IOC4_SHADOW_DCD 0x00800000 /* Data carrier detect */
-#define IOC4_SHADOW_DTR 0x01000000 /* Data terminal ready */
-#define IOC4_SHADOW_RTS 0x02000000 /* Request to send */
-#define IOC4_SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */
-#define IOC4_SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */
-#define IOC4_SHADOW_LOOP 0x10000000 /* Loopback enabled */
-
-/* Bitmasks for IOC4_SRTR_<3:0> */
-#define IOC4_SRTR_CNT 0x00000fff /* Reload value for RX timer */
-#define IOC4_SRTR_CNT_VAL 0x0fff0000 /* Current value of RX timer */
-#define IOC4_SRTR_CNT_VAL_SHIFT 16
-#define IOC4_SRTR_HZ 16000 /* SRTR clock frequency */
-
-/* Serial port register map used for DMA and PIO serial I/O */
-struct ioc4_serialregs {
- uint32_t sscr;
- uint32_t stpir;
- uint32_t stcir;
- uint32_t srpir;
- uint32_t srcir;
- uint32_t srtr;
- uint32_t shadow;
-};
-
-/* IOC4 UART register map */
-struct ioc4_uartregs {
- char i4u_lcr;
- union {
- char iir; /* read only */
- char fcr; /* write only */
- } u3;
- union {
- char ier; /* DLAB == 0 */
- char dlm; /* DLAB == 1 */
- } u2;
- union {
- char rbr; /* read only, DLAB == 0 */
- char thr; /* write only, DLAB == 0 */
- char dll; /* DLAB == 1 */
- } u1;
- char i4u_scr;
- char i4u_msr;
- char i4u_lsr;
- char i4u_mcr;
-};
-
-/* short names */
-#define i4u_dll u1.dll
-#define i4u_ier u2.ier
-#define i4u_dlm u2.dlm
-#define i4u_fcr u3.fcr
-
-/* Serial port registers used for DMA serial I/O */
-struct ioc4_serial {
- uint32_t sbbr01_l;
- uint32_t sbbr01_h;
- uint32_t sbbr23_l;
- uint32_t sbbr23_h;
-
- struct ioc4_serialregs port_0;
- struct ioc4_serialregs port_1;
- struct ioc4_serialregs port_2;
- struct ioc4_serialregs port_3;
- struct ioc4_uartregs uart_0;
- struct ioc4_uartregs uart_1;
- struct ioc4_uartregs uart_2;
- struct ioc4_uartregs uart_3;
-};
-
-/* UART clock speed */
-#define IOC4_SER_XIN_CLK_66 66666667
-#define IOC4_SER_XIN_CLK_33 33333333
-
-#define IOC4_W_IES 0
-#define IOC4_W_IEC 1
-
-typedef void ioc4_intr_func_f(void *, uint32_t);
-typedef ioc4_intr_func_f *ioc4_intr_func_t;
-
-static unsigned int Num_of_ioc4_cards;
-
-/* defining this will get you LOTS of great debug info */
-//#define DEBUG_INTERRUPTS
-#define DPRINT_CONFIG(_x...) ;
-//#define DPRINT_CONFIG(_x...) printk _x
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/* number of characters we want to transmit to the lower level at a time */
-#define IOC4_MAX_CHARS 256
-#define IOC4_FIFO_CHARS 255
-
-/* Device name we're using */
-#define DEVICE_NAME_RS232 "ttyIOC"
-#define DEVICE_NAME_RS422 "ttyAIOC"
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR_RS232 50
-#define DEVICE_MINOR_RS422 84
-
-
-/* register offsets */
-#define IOC4_SERIAL_OFFSET 0x300
-
-/* flags for next_char_state */
-#define NCS_BREAK 0x1
-#define NCS_PARITY 0x2
-#define NCS_FRAMING 0x4
-#define NCS_OVERRUN 0x8
-
-/* cause we need SOME parameters ... */
-#define MIN_BAUD_SUPPORTED 1200
-#define MAX_BAUD_SUPPORTED 115200
-
-/* protocol types supported */
-#define PROTO_RS232 3
-#define PROTO_RS422 7
-
-/* Notification types */
-#define N_DATA_READY 0x01
-#define N_OUTPUT_LOWAT 0x02
-#define N_BREAK 0x04
-#define N_PARITY_ERROR 0x08
-#define N_FRAMING_ERROR 0x10
-#define N_OVERRUN_ERROR 0x20
-#define N_DDCD 0x40
-#define N_DCTS 0x80
-
-#define N_ALL_INPUT (N_DATA_READY | N_BREAK | \
- N_PARITY_ERROR | N_FRAMING_ERROR | \
- N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define N_ALL_OUTPUT N_OUTPUT_LOWAT
-
-#define N_ALL_ERRORS (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)
-
-#define N_ALL (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK | \
- N_PARITY_ERROR | N_FRAMING_ERROR | \
- N_OVERRUN_ERROR | N_DDCD | N_DCTS)
-
-#define SER_DIVISOR(_x, clk) (((clk) + (_x) * 8) / ((_x) * 16))
-#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
-
-/* Some masks */
-#define LCR_MASK_BITS_CHAR (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
- | UART_LCR_WLEN7 | UART_LCR_WLEN8)
-#define LCR_MASK_STOP_BITS (UART_LCR_STOP)
-
-#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)
-#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)
-
-/* Default to 4k buffers */
-#ifdef IOC4_1K_BUFFERS
-#define RING_BUF_SIZE 1024
-#define IOC4_BUF_SIZE_BIT 0
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K
-#else
-#define RING_BUF_SIZE 4096
-#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE
-#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K
-#endif
-
-#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)
-
-/*
- * This is the entry saved by the driver - one per card
- */
-
-#define UART_PORT_MIN 0
-#define UART_PORT_RS232 UART_PORT_MIN
-#define UART_PORT_RS422 1
-#define UART_PORT_COUNT 2 /* one for each mode */
-
-struct ioc4_control {
- int ic_irq;
- struct {
- /* uart ports are allocated here - 1 for rs232, 1 for rs422 */
- struct uart_port icp_uart_port[UART_PORT_COUNT];
- /* Handy reference material */
- struct ioc4_port *icp_port;
- } ic_port[IOC4_NUM_SERIAL_PORTS];
- struct ioc4_soft *ic_soft;
-};
-
-/*
- * per-IOC4 data structure
- */
-#define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t))
-struct ioc4_soft {
- struct ioc4_misc_regs __iomem *is_ioc4_misc_addr;
- struct ioc4_serial __iomem *is_ioc4_serial_addr;
-
- /* Each interrupt type has an entry in the array */
- struct ioc4_intr_type {
-
- /*
- * Each in-use entry in this array contains at least
- * one nonzero bit in sd_bits; no two entries in this
- * array have overlapping sd_bits values.
- */
- struct ioc4_intr_info {
- uint32_t sd_bits;
- ioc4_intr_func_f *sd_intr;
- void *sd_info;
- } is_intr_info[MAX_IOC4_INTR_ENTS];
-
- /* Number of entries active in the above array */
- atomic_t is_num_intrs;
- } is_intr_type[IOC4_NUM_INTR_TYPES];
-
- /* is_ir_lock must be held while
- * modifying sio_ie values, so
- * we can be sure that sio_ie is
- * not changing when we read it
- * along with sio_ir.
- */
- spinlock_t is_ir_lock; /* SIO_IE[SC] mod lock */
-};
-
-/* Local port info for each IOC4 serial ports */
-struct ioc4_port {
- struct uart_port *ip_port; /* current active port ptr */
- /* Ptrs for all ports */
- struct uart_port *ip_all_ports[UART_PORT_COUNT];
- /* Back ptrs for this port */
- struct ioc4_control *ip_control;
- struct pci_dev *ip_pdev;
- struct ioc4_soft *ip_ioc4_soft;
-
- /* pci mem addresses */
- struct ioc4_misc_regs __iomem *ip_mem;
- struct ioc4_serial __iomem *ip_serial;
- struct ioc4_serialregs __iomem *ip_serial_regs;
- struct ioc4_uartregs __iomem *ip_uart_regs;
-
- /* Ring buffer page for this port */
- dma_addr_t ip_dma_ringbuf;
- /* vaddr of ring buffer */
- struct ring_buffer *ip_cpu_ringbuf;
-
- /* Rings for this port */
- struct ring *ip_inring;
- struct ring *ip_outring;
-
- /* Hook to port specific values */
- struct hooks *ip_hooks;
-
- spinlock_t ip_lock;
-
- /* Various rx/tx parameters */
- int ip_baud;
- int ip_tx_lowat;
- int ip_rx_timeout;
-
- /* Copy of notification bits */
- int ip_notify;
-
- /* Shadow copies of various registers so we don't need to PIO
- * read them constantly
- */
- uint32_t ip_ienb; /* Enabled interrupts */
- uint32_t ip_sscr;
- uint32_t ip_tx_prod;
- uint32_t ip_rx_cons;
- int ip_pci_bus_speed;
- unsigned char ip_flags;
-};
-
-/* tx low water mark. We need to notify the driver whenever tx is getting
- * close to empty so it can refill the tx buffer and keep things going.
- * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
- * have no trouble getting in more chars in time (I certainly hope so).
- */
-#define TX_LOWAT_LATENCY 1000
-#define TX_LOWAT_HZ (1000000 / TX_LOWAT_LATENCY)
-#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
-
-/* Flags per port */
-#define INPUT_HIGH 0x01
-#define DCD_ON 0x02
-#define LOWAT_WRITTEN 0x04
-#define READ_ABORTED 0x08
-#define PORT_ACTIVE 0x10
-#define PORT_INACTIVE 0 /* This is the value when "off" */
-
-
-/* Since each port has different register offsets and bitmasks
- * for everything, we'll store those that we need in tables so we
- * don't have to be constantly checking the port we are dealing with.
- */
-struct hooks {
- uint32_t intr_delta_dcd;
- uint32_t intr_delta_cts;
- uint32_t intr_tx_mt;
- uint32_t intr_rx_timer;
- uint32_t intr_rx_high;
- uint32_t intr_tx_explicit;
- uint32_t intr_dma_error;
- uint32_t intr_clear;
- uint32_t intr_all;
- int rs422_select_pin;
-};
-
-static struct hooks hooks_array[IOC4_NUM_SERIAL_PORTS] = {
- /* Values for port 0 */
- {
- IOC4_SIO_IR_S0_DELTA_DCD, IOC4_SIO_IR_S0_DELTA_CTS,
- IOC4_SIO_IR_S0_TX_MT, IOC4_SIO_IR_S0_RX_TIMER,
- IOC4_SIO_IR_S0_RX_HIGH, IOC4_SIO_IR_S0_TX_EXPLICIT,
- IOC4_OTHER_IR_S0_MEMERR,
- (IOC4_SIO_IR_S0_TX_MT | IOC4_SIO_IR_S0_RX_FULL |
- IOC4_SIO_IR_S0_RX_HIGH | IOC4_SIO_IR_S0_RX_TIMER |
- IOC4_SIO_IR_S0_DELTA_DCD | IOC4_SIO_IR_S0_DELTA_CTS |
- IOC4_SIO_IR_S0_INT | IOC4_SIO_IR_S0_TX_EXPLICIT),
- IOC4_SIO_IR_S0, IOC4_GPPR_UART0_MODESEL_PIN,
- },
-
- /* Values for port 1 */
- {
- IOC4_SIO_IR_S1_DELTA_DCD, IOC4_SIO_IR_S1_DELTA_CTS,
- IOC4_SIO_IR_S1_TX_MT, IOC4_SIO_IR_S1_RX_TIMER,
- IOC4_SIO_IR_S1_RX_HIGH, IOC4_SIO_IR_S1_TX_EXPLICIT,
- IOC4_OTHER_IR_S1_MEMERR,
- (IOC4_SIO_IR_S1_TX_MT | IOC4_SIO_IR_S1_RX_FULL |
- IOC4_SIO_IR_S1_RX_HIGH | IOC4_SIO_IR_S1_RX_TIMER |
- IOC4_SIO_IR_S1_DELTA_DCD | IOC4_SIO_IR_S1_DELTA_CTS |
- IOC4_SIO_IR_S1_INT | IOC4_SIO_IR_S1_TX_EXPLICIT),
- IOC4_SIO_IR_S1, IOC4_GPPR_UART1_MODESEL_PIN,
- },
-
- /* Values for port 2 */
- {
- IOC4_SIO_IR_S2_DELTA_DCD, IOC4_SIO_IR_S2_DELTA_CTS,
- IOC4_SIO_IR_S2_TX_MT, IOC4_SIO_IR_S2_RX_TIMER,
- IOC4_SIO_IR_S2_RX_HIGH, IOC4_SIO_IR_S2_TX_EXPLICIT,
- IOC4_OTHER_IR_S2_MEMERR,
- (IOC4_SIO_IR_S2_TX_MT | IOC4_SIO_IR_S2_RX_FULL |
- IOC4_SIO_IR_S2_RX_HIGH | IOC4_SIO_IR_S2_RX_TIMER |
- IOC4_SIO_IR_S2_DELTA_DCD | IOC4_SIO_IR_S2_DELTA_CTS |
- IOC4_SIO_IR_S2_INT | IOC4_SIO_IR_S2_TX_EXPLICIT),
- IOC4_SIO_IR_S2, IOC4_GPPR_UART2_MODESEL_PIN,
- },
-
- /* Values for port 3 */
- {
- IOC4_SIO_IR_S3_DELTA_DCD, IOC4_SIO_IR_S3_DELTA_CTS,
- IOC4_SIO_IR_S3_TX_MT, IOC4_SIO_IR_S3_RX_TIMER,
- IOC4_SIO_IR_S3_RX_HIGH, IOC4_SIO_IR_S3_TX_EXPLICIT,
- IOC4_OTHER_IR_S3_MEMERR,
- (IOC4_SIO_IR_S3_TX_MT | IOC4_SIO_IR_S3_RX_FULL |
- IOC4_SIO_IR_S3_RX_HIGH | IOC4_SIO_IR_S3_RX_TIMER |
- IOC4_SIO_IR_S3_DELTA_DCD | IOC4_SIO_IR_S3_DELTA_CTS |
- IOC4_SIO_IR_S3_INT | IOC4_SIO_IR_S3_TX_EXPLICIT),
- IOC4_SIO_IR_S3, IOC4_GPPR_UART3_MODESEL_PIN,
- }
-};
-
-/* A ring buffer entry */
-struct ring_entry {
- union {
- struct {
- uint32_t alldata;
- uint32_t allsc;
- } all;
- struct {
- char data[4]; /* data bytes */
- char sc[4]; /* status/control */
- } s;
- } u;
-};
-
-/* Test the valid bits in any of the 4 sc chars using "allsc" member */
-#define RING_ANY_VALID \
- ((uint32_t)(IOC4_RXSB_MODEM_VALID | IOC4_RXSB_DATA_VALID) * 0x01010101)
-
-#define ring_sc u.s.sc
-#define ring_data u.s.data
-#define ring_allsc u.all.allsc
-
-/* Number of entries per ring buffer. */
-#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
-
-/* An individual ring */
-struct ring {
- struct ring_entry entries[ENTRIES_PER_RING];
-};
-
-/* The whole enchilada */
-struct ring_buffer {
- struct ring TX_0_OR_2;
- struct ring RX_0_OR_2;
- struct ring TX_1_OR_3;
- struct ring RX_1_OR_3;
-};
-
-/* Get a ring from a port struct */
-#define RING(_p, _wh) &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
-
-/* Infinite loop detection.
- */
-#define MAXITER 10000000
-
-/* Prototypes */
-static void receive_chars(struct uart_port *);
-static void handle_intr(void *arg, uint32_t sio_ir);
-
-/*
- * port_is_active - determines if this port is currently active
- * @port: ptr to soft struct for this port
- * @uart_port: uart port to test for
- */
-static inline int port_is_active(struct ioc4_port *port,
- struct uart_port *uart_port)
-{
- if (port) {
- if ((port->ip_flags & PORT_ACTIVE)
- && (port->ip_port == uart_port))
- return 1;
- }
- return 0;
-}
-
-
-/**
- * write_ireg - write the interrupt regs
- * @ioc4_soft: ptr to soft struct for this port
- * @val: value to write
- * @which: which register
- * @type: which ireg set
- */
-static inline void
-write_ireg(struct ioc4_soft *ioc4_soft, uint32_t val, int which, int type)
-{
- struct ioc4_misc_regs __iomem *mem = ioc4_soft->is_ioc4_misc_addr;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc4_soft->is_ir_lock, flags);
-
- switch (type) {
- case IOC4_SIO_INTR_TYPE:
- switch (which) {
- case IOC4_W_IES:
- writel(val, &mem->sio_ies.raw);
- break;
-
- case IOC4_W_IEC:
- writel(val, &mem->sio_iec.raw);
- break;
- }
- break;
-
- case IOC4_OTHER_INTR_TYPE:
- switch (which) {
- case IOC4_W_IES:
- writel(val, &mem->other_ies.raw);
- break;
-
- case IOC4_W_IEC:
- writel(val, &mem->other_iec.raw);
- break;
- }
- break;
-
- default:
- break;
- }
- spin_unlock_irqrestore(&ioc4_soft->is_ir_lock, flags);
-}
-
-/**
- * set_baud - Baud rate setting code
- * @port: port to set
- * @baud: baud rate to use
- */
-static int set_baud(struct ioc4_port *port, int baud)
-{
- int actual_baud;
- int diff;
- int lcr;
- unsigned short divisor;
- struct ioc4_uartregs __iomem *uart;
-
- divisor = SER_DIVISOR(baud, port->ip_pci_bus_speed);
- if (!divisor)
- return 1;
- actual_baud = DIVISOR_TO_BAUD(divisor, port->ip_pci_bus_speed);
-
- diff = actual_baud - baud;
- if (diff < 0)
- diff = -diff;
-
- /* If we're within 1%, we've found a match */
- if (diff * 100 > actual_baud)
- return 1;
-
- uart = port->ip_uart_regs;
- lcr = readb(&uart->i4u_lcr);
- writeb(lcr | UART_LCR_DLAB, &uart->i4u_lcr);
- writeb((unsigned char)divisor, &uart->i4u_dll);
- writeb((unsigned char)(divisor >> 8), &uart->i4u_dlm);
- writeb(lcr, &uart->i4u_lcr);
- return 0;
-}
-
-
-/**
- * get_ioc4_port - given a uart port, return the control structure
- * @port: uart port
- * @set: set this port as current
- */
-static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set)
-{
- struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev);
- struct ioc4_control *control = idd->idd_serial_data;
- struct ioc4_port *port;
- int port_num, port_type;
-
- if (control) {
- for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS;
- port_num++ ) {
- port = control->ic_port[port_num].icp_port;
- if (!port)
- continue;
- for (port_type = UART_PORT_MIN;
- port_type < UART_PORT_COUNT;
- port_type++) {
- if (the_port == port->ip_all_ports
- [port_type]) {
- /* set local copy */
- if (set) {
- port->ip_port = the_port;
- }
- return port;
- }
- }
- }
- }
- return NULL;
-}
-
-/* The IOC4 hardware provides no atomic way to determine if interrupts
- * are pending since two reads are required to do so. The handler must
- * read the SIO_IR and the SIO_IES, and take the logical and of the
- * two. When this value is zero, all interrupts have been serviced and
- * the handler may return.
- *
- * This has the unfortunate "hole" that, if some other CPU or
- * some other thread or some higher level interrupt manages to
- * modify SIO_IE between our reads of SIO_IR and SIO_IE, we may
- * think we have observed SIO_IR&SIO_IE==0 when in fact this
- * condition never really occurred.
- *
- * To solve this, we use a simple spinlock that must be held
- * whenever modifying SIO_IE; holding this lock while observing
- * both SIO_IR and SIO_IE guarantees that we do not falsely
- * conclude that no enabled interrupts are pending.
- */
-
-static inline uint32_t
-pending_intrs(struct ioc4_soft *soft, int type)
-{
- struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
- unsigned long flag;
- uint32_t intrs = 0;
-
- BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
- || (type == IOC4_OTHER_INTR_TYPE)));
-
- spin_lock_irqsave(&soft->is_ir_lock, flag);
-
- switch (type) {
- case IOC4_SIO_INTR_TYPE:
- intrs = readl(&mem->sio_ir.raw) & readl(&mem->sio_ies.raw);
- break;
-
- case IOC4_OTHER_INTR_TYPE:
- intrs = readl(&mem->other_ir.raw) & readl(&mem->other_ies.raw);
-
- /* Don't process any ATA interrupte */
- intrs &= ~(IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
- break;
-
- default:
- break;
- }
- spin_unlock_irqrestore(&soft->is_ir_lock, flag);
- return intrs;
-}
-
-/**
- * port_init - Initialize the sio and ioc4 hardware for a given port
- * called per port from attach...
- * @port: port to initialize
- */
-static inline int port_init(struct ioc4_port *port)
-{
- uint32_t sio_cr;
- struct hooks *hooks = port->ip_hooks;
- struct ioc4_uartregs __iomem *uart;
-
- /* Idle the IOC4 serial interface */
- writel(IOC4_SSCR_RESET, &port->ip_serial_regs->sscr);
-
- /* Wait until any pending bus activity for this port has ceased */
- do
- sio_cr = readl(&port->ip_mem->sio_cr.raw);
- while (!(sio_cr & IOC4_SIO_CR_SIO_DIAG_IDLE));
-
- /* Finish reset sequence */
- writel(0, &port->ip_serial_regs->sscr);
-
- /* Once RESET is done, reload cached tx_prod and rx_cons values
- * and set rings to empty by making prod == cons
- */
- port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
- writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
- port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
- writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
- /* Disable interrupts for this 16550 */
- uart = port->ip_uart_regs;
- writeb(0, &uart->i4u_lcr);
- writeb(0, &uart->i4u_ier);
-
- /* Set the default baud */
- set_baud(port, port->ip_baud);
-
- /* Set line control to 8 bits no parity */
- writeb(UART_LCR_WLEN8 | 0, &uart->i4u_lcr);
- /* UART_LCR_STOP == 1 stop */
-
- /* Enable the FIFOs */
- writeb(UART_FCR_ENABLE_FIFO, &uart->i4u_fcr);
- /* then reset 16550 FIFOs */
- writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
- &uart->i4u_fcr);
-
- /* Clear modem control register */
- writeb(0, &uart->i4u_mcr);
-
- /* Clear deltas in modem status register */
- readb(&uart->i4u_msr);
-
- /* Only do this once per port pair */
- if (port->ip_hooks == &hooks_array[0]
- || port->ip_hooks == &hooks_array[2]) {
- unsigned long ring_pci_addr;
- uint32_t __iomem *sbbr_l;
- uint32_t __iomem *sbbr_h;
-
- if (port->ip_hooks == &hooks_array[0]) {
- sbbr_l = &port->ip_serial->sbbr01_l;
- sbbr_h = &port->ip_serial->sbbr01_h;
- } else {
- sbbr_l = &port->ip_serial->sbbr23_l;
- sbbr_h = &port->ip_serial->sbbr23_h;
- }
-
- ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
- DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
- __func__, ring_pci_addr));
-
- writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
- writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
- }
-
- /* Set the receive timeout value to 10 msec */
- writel(IOC4_SRTR_HZ / 100, &port->ip_serial_regs->srtr);
-
- /* Set rx threshold, enable DMA */
- /* Set high water mark at 3/4 of full ring */
- port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
- /* Disable and clear all serial related interrupt bits */
- write_ireg(port->ip_ioc4_soft, hooks->intr_clear,
- IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
- port->ip_ienb &= ~hooks->intr_clear;
- writel(hooks->intr_clear, &port->ip_mem->sio_ir.raw);
- return 0;
-}
-
-/**
- * handle_dma_error_intr - service any pending DMA error interrupts for the
- * given port - 2nd level called via sd_intr
- * @arg: handler arg
- * @other_ir: ioc4regs
- */
-static void handle_dma_error_intr(void *arg, uint32_t other_ir)
-{
- struct ioc4_port *port = (struct ioc4_port *)arg;
- struct hooks *hooks = port->ip_hooks;
- unsigned long flags;
-
- spin_lock_irqsave(&port->ip_lock, flags);
-
- /* ACK the interrupt */
- writel(hooks->intr_dma_error, &port->ip_mem->other_ir.raw);
-
- if (readl(&port->ip_mem->pci_err_addr_l.raw) & IOC4_PCI_ERR_ADDR_VLD) {
- printk(KERN_ERR
- "PCI error address is 0x%llx, "
- "master is serial port %c %s\n",
- (((uint64_t)readl(&port->ip_mem->pci_err_addr_h)
- << 32)
- | readl(&port->ip_mem->pci_err_addr_l.raw))
- & IOC4_PCI_ERR_ADDR_ADDR_MSK, '1' +
- ((char)(readl(&port->ip_mem->pci_err_addr_l.raw) &
- IOC4_PCI_ERR_ADDR_MST_NUM_MSK) >> 1),
- (readl(&port->ip_mem->pci_err_addr_l.raw)
- & IOC4_PCI_ERR_ADDR_MST_TYP_MSK)
- ? "RX" : "TX");
-
- if (readl(&port->ip_mem->pci_err_addr_l.raw)
- & IOC4_PCI_ERR_ADDR_MUL_ERR) {
- printk(KERN_ERR
- "Multiple errors occurred\n");
- }
- }
- spin_unlock_irqrestore(&port->ip_lock, flags);
-
- /* Re-enable DMA error interrupts */
- write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error, IOC4_W_IES,
- IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * intr_connect - interrupt connect function
- * @soft: soft struct for this card
- * @type: interrupt type
- * @intrbits: bit pattern to set
- * @intr: handler function
- * @info: handler arg
- */
-static void
-intr_connect(struct ioc4_soft *soft, int type,
- uint32_t intrbits, ioc4_intr_func_f * intr, void *info)
-{
- int i;
- struct ioc4_intr_info *intr_ptr;
-
- BUG_ON(!((type == IOC4_SIO_INTR_TYPE)
- || (type == IOC4_OTHER_INTR_TYPE)));
-
- i = atomic_inc_return(&soft-> is_intr_type[type].is_num_intrs) - 1;
- BUG_ON(!(i < MAX_IOC4_INTR_ENTS || (printk("i %d\n", i), 0)));
-
- /* Save off the lower level interrupt handler */
- intr_ptr = &soft->is_intr_type[type].is_intr_info[i];
- intr_ptr->sd_bits = intrbits;
- intr_ptr->sd_intr = intr;
- intr_ptr->sd_info = info;
-}
-
-/**
- * ioc4_intr - Top level IOC4 interrupt handler.
- * @irq: irq value
- * @arg: handler arg
- */
-
-static irqreturn_t ioc4_intr(int irq, void *arg)
-{
- struct ioc4_soft *soft;
- uint32_t this_ir, this_mir;
- int xx, num_intrs = 0;
- int intr_type;
- int handled = 0;
- struct ioc4_intr_info *intr_info;
-
- soft = arg;
- for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) {
- num_intrs = (int)atomic_read(
- &soft->is_intr_type[intr_type].is_num_intrs);
-
- this_mir = this_ir = pending_intrs(soft, intr_type);
-
- /* Farm out the interrupt to the various drivers depending on
- * which interrupt bits are set.
- */
- for (xx = 0; xx < num_intrs; xx++) {
- intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
- this_mir = this_ir & intr_info->sd_bits;
- if (this_mir) {
- /* Disable owned interrupts, call handler */
- handled++;
- write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
- intr_type);
- intr_info->sd_intr(intr_info->sd_info, this_mir);
- this_ir &= ~this_mir;
- }
- }
- }
-#ifdef DEBUG_INTERRUPTS
- {
- struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr;
- unsigned long flag;
-
- spin_lock_irqsave(&soft->is_ir_lock, flag);
- printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
- "other_ir 0x%x other_ies 0x%x mask 0x%x\n",
- __func__, __LINE__,
- (void *)mem, readl(&mem->sio_ir.raw),
- readl(&mem->sio_ies.raw),
- readl(&mem->other_ir.raw),
- readl(&mem->other_ies.raw),
- IOC4_OTHER_IR_ATA_INT | IOC4_OTHER_IR_ATA_MEMERR);
- spin_unlock_irqrestore(&soft->is_ir_lock, flag);
- }
-#endif
- return handled ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/**
- * ioc4_attach_local - Device initialization.
- * Called at *_attach() time for each
- * IOC4 with serial ports in the system.
- * @idd: Master module data for this IOC4
- */
-static inline int ioc4_attach_local(struct ioc4_driver_data *idd)
-{
- struct ioc4_port *port;
- struct ioc4_port *ports[IOC4_NUM_SERIAL_PORTS];
- int port_number;
- uint16_t ioc4_revid_min = 62;
- uint16_t ioc4_revid;
- struct pci_dev *pdev = idd->idd_pdev;
- struct ioc4_control* control = idd->idd_serial_data;
- struct ioc4_soft *soft = control->ic_soft;
- void __iomem *ioc4_misc = idd->idd_misc_regs;
- void __iomem *ioc4_serial = soft->is_ioc4_serial_addr;
-
- /* IOC4 firmware must be at least rev 62 */
- pci_read_config_word(pdev, PCI_COMMAND_SPECIAL, &ioc4_revid);
-
- printk(KERN_INFO "IOC4 firmware revision %d\n", ioc4_revid);
- if (ioc4_revid < ioc4_revid_min) {
- printk(KERN_WARNING
- "IOC4 serial not supported on firmware rev %d, "
- "please upgrade to rev %d or higher\n",
- ioc4_revid, ioc4_revid_min);
- return -EPERM;
- }
- BUG_ON(ioc4_misc == NULL);
- BUG_ON(ioc4_serial == NULL);
-
- /* Create port structures for each port */
- for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
- port_number++) {
- port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
- if (!port) {
- printk(KERN_WARNING
- "IOC4 serial memory not available for port\n");
- goto free;
- }
- spin_lock_init(&port->ip_lock);
-
- /* we need to remember the previous ones, to point back to
- * them farther down - setting up the ring buffers.
- */
- ports[port_number] = port;
-
- /* Allocate buffers and jumpstart the hardware. */
- control->ic_port[port_number].icp_port = port;
- port->ip_ioc4_soft = soft;
- port->ip_pdev = pdev;
- port->ip_ienb = 0;
- /* Use baud rate calculations based on detected PCI
- * bus speed. Simply test whether the PCI clock is
- * running closer to 66MHz or 33MHz.
- */
- if (idd->count_period/IOC4_EXTINT_COUNT_DIVISOR < 20) {
- port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_66;
- } else {
- port->ip_pci_bus_speed = IOC4_SER_XIN_CLK_33;
- }
- port->ip_baud = 9600;
- port->ip_control = control;
- port->ip_mem = ioc4_misc;
- port->ip_serial = ioc4_serial;
-
- /* point to the right hook */
- port->ip_hooks = &hooks_array[port_number];
-
- /* Get direct hooks to the serial regs and uart regs
- * for this port
- */
- switch (port_number) {
- case 0:
- port->ip_serial_regs = &(port->ip_serial->port_0);
- port->ip_uart_regs = &(port->ip_serial->uart_0);
- break;
- case 1:
- port->ip_serial_regs = &(port->ip_serial->port_1);
- port->ip_uart_regs = &(port->ip_serial->uart_1);
- break;
- case 2:
- port->ip_serial_regs = &(port->ip_serial->port_2);
- port->ip_uart_regs = &(port->ip_serial->uart_2);
- break;
- default:
- case 3:
- port->ip_serial_regs = &(port->ip_serial->port_3);
- port->ip_uart_regs = &(port->ip_serial->uart_3);
- break;
- }
-
- /* ring buffers are 1 to a pair of ports */
- if (port_number && (port_number & 1)) {
- /* odd use the evens buffer */
- port->ip_dma_ringbuf =
- ports[port_number - 1]->ip_dma_ringbuf;
- port->ip_cpu_ringbuf =
- ports[port_number - 1]->ip_cpu_ringbuf;
- port->ip_inring = RING(port, RX_1_OR_3);
- port->ip_outring = RING(port, TX_1_OR_3);
-
- } else {
- if (port->ip_dma_ringbuf == 0) {
- port->ip_cpu_ringbuf = pci_alloc_consistent
- (pdev, TOTAL_RING_BUF_SIZE,
- &port->ip_dma_ringbuf);
-
- }
- BUG_ON(!((((int64_t)port->ip_dma_ringbuf) &
- (TOTAL_RING_BUF_SIZE - 1)) == 0));
- DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
- "ip_dma_ringbuf 0x%p\n",
- __func__,
- (void *)port->ip_cpu_ringbuf,
- (void *)port->ip_dma_ringbuf));
- port->ip_inring = RING(port, RX_0_OR_2);
- port->ip_outring = RING(port, TX_0_OR_2);
- }
- DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
- __func__,
- port_number, (void *)port, (void *)control));
- DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
- (void *)port->ip_serial_regs,
- (void *)port->ip_uart_regs));
-
- /* Initialize the hardware for IOC4 */
- port_init(port);
-
- DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
- "outring 0x%p\n",
- __func__,
- port_number, (void *)port,
- (void *)port->ip_inring,
- (void *)port->ip_outring));
-
- /* Attach interrupt handlers */
- intr_connect(soft, IOC4_SIO_INTR_TYPE,
- GET_SIO_IR(port_number),
- handle_intr, port);
-
- intr_connect(soft, IOC4_OTHER_INTR_TYPE,
- GET_OTHER_IR(port_number),
- handle_dma_error_intr, port);
- }
- return 0;
-
-free:
- while (port_number)
- kfree(ports[--port_number]);
- return -ENOMEM;
-}
-
-/**
- * enable_intrs - enable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void enable_intrs(struct ioc4_port *port, uint32_t mask)
-{
- struct hooks *hooks = port->ip_hooks;
-
- if ((port->ip_ienb & mask) != mask) {
- write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IES,
- IOC4_SIO_INTR_TYPE);
- port->ip_ienb |= mask;
- }
-
- if (port->ip_ienb)
- write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
- IOC4_W_IES, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * local_open - local open a port
- * @port: port to open
- */
-static inline int local_open(struct ioc4_port *port)
-{
- int spiniter = 0;
-
- port->ip_flags = PORT_ACTIVE;
-
- /* Pause the DMA interface if necessary */
- if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
- writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
- &port->ip_serial_regs->sscr);
- while((readl(&port->ip_serial_regs-> sscr)
- & IOC4_SSCR_PAUSE_STATE) == 0) {
- spiniter++;
- if (spiniter > MAXITER) {
- port->ip_flags = PORT_INACTIVE;
- return -1;
- }
- }
- }
-
- /* Reset the input fifo. If the uart received chars while the port
- * was closed and DMA is not enabled, the uart may have a bunch of
- * chars hanging around in its rx fifo which will not be discarded
- * by rclr in the upper layer. We must get rid of them here.
- */
- writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
- &port->ip_uart_regs->i4u_fcr);
-
- writeb(UART_LCR_WLEN8, &port->ip_uart_regs->i4u_lcr);
- /* UART_LCR_STOP == 1 stop */
-
- /* Re-enable DMA, set default threshold to intr whenever there is
- * data available.
- */
- port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
- port->ip_sscr |= 1; /* default threshold */
-
- /* Plug in the new sscr. This implicitly clears the DMA_PAUSE
- * flag if it was set above
- */
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- port->ip_tx_lowat = 1;
- return 0;
-}
-
-/**
- * set_rx_timeout - Set rx timeout and threshold values.
- * @port: port to use
- * @timeout: timeout value in ticks
- */
-static inline int set_rx_timeout(struct ioc4_port *port, int timeout)
-{
- int threshold;
-
- port->ip_rx_timeout = timeout;
-
- /* Timeout is in ticks. Let's figure out how many chars we
- * can receive at the current baud rate in that interval
- * and set the rx threshold to that amount. There are 4 chars
- * per ring entry, so we'll divide the number of chars that will
- * arrive in timeout by 4.
- * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
- */
- threshold = timeout * port->ip_baud / 4000;
- if (threshold == 0)
- threshold = 1; /* otherwise we'll intr all the time! */
-
- if ((unsigned)threshold > (unsigned)IOC4_SSCR_RX_THRESHOLD)
- return 1;
-
- port->ip_sscr &= ~IOC4_SSCR_RX_THRESHOLD;
- port->ip_sscr |= threshold;
-
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
- /* Now set the rx timeout to the given value
- * again timeout * IOC4_SRTR_HZ / HZ
- */
- timeout = timeout * IOC4_SRTR_HZ / 100;
- if (timeout > IOC4_SRTR_CNT)
- timeout = IOC4_SRTR_CNT;
-
- writel(timeout, &port->ip_serial_regs->srtr);
- return 0;
-}
-
-/**
- * config_port - config the hardware
- * @port: port to config
- * @baud: baud rate for the port
- * @byte_size: data size
- * @stop_bits: number of stop bits
- * @parenb: parity enable ?
- * @parodd: odd parity ?
- */
-static inline int
-config_port(struct ioc4_port *port,
- int baud, int byte_size, int stop_bits, int parenb, int parodd)
-{
- char lcr, sizebits;
- int spiniter = 0;
-
- DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
- __func__, baud, byte_size, stop_bits, parenb, parodd));
-
- if (set_baud(port, baud))
- return 1;
-
- switch (byte_size) {
- case 5:
- sizebits = UART_LCR_WLEN5;
- break;
- case 6:
- sizebits = UART_LCR_WLEN6;
- break;
- case 7:
- sizebits = UART_LCR_WLEN7;
- break;
- case 8:
- sizebits = UART_LCR_WLEN8;
- break;
- default:
- return 1;
- }
-
- /* Pause the DMA interface if necessary */
- if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
- writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
- &port->ip_serial_regs->sscr);
- while((readl(&port->ip_serial_regs->sscr)
- & IOC4_SSCR_PAUSE_STATE) == 0) {
- spiniter++;
- if (spiniter > MAXITER)
- return -1;
- }
- }
-
- /* Clear relevant fields in lcr */
- lcr = readb(&port->ip_uart_regs->i4u_lcr);
- lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
- UART_LCR_PARITY | LCR_MASK_STOP_BITS);
-
- /* Set byte size in lcr */
- lcr |= sizebits;
-
- /* Set parity */
- if (parenb) {
- lcr |= UART_LCR_PARITY;
- if (!parodd)
- lcr |= UART_LCR_EPAR;
- }
-
- /* Set stop bits */
- if (stop_bits)
- lcr |= UART_LCR_STOP /* 2 stop bits */ ;
-
- writeb(lcr, &port->ip_uart_regs->i4u_lcr);
-
- /* Re-enable the DMA interface if necessary */
- if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
- port->ip_baud = baud;
-
- /* When we get within this number of ring entries of filling the
- * entire ring on tx, place an EXPLICIT intr to generate a lowat
- * notification when output has drained.
- */
- port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
- if (port->ip_tx_lowat == 0)
- port->ip_tx_lowat = 1;
-
- set_rx_timeout(port, 2);
-
- return 0;
-}
-
-/**
- * do_write - Write bytes to the port. Returns the number of bytes
- * actually written. Called from transmit_chars
- * @port: port to use
- * @buf: the stuff to write
- * @len: how many bytes in 'buf'
- */
-static inline int do_write(struct ioc4_port *port, char *buf, int len)
-{
- int prod_ptr, cons_ptr, total = 0;
- struct ring *outring;
- struct ring_entry *entry;
- struct hooks *hooks = port->ip_hooks;
-
- BUG_ON(!(len >= 0));
-
- prod_ptr = port->ip_tx_prod;
- cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
- outring = port->ip_outring;
-
- /* Maintain a 1-entry red-zone. The ring buffer is full when
- * (cons - prod) % ring_size is 1. Rather than do this subtraction
- * in the body of the loop, I'll do it now.
- */
- cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
-
- /* Stuff the bytes into the output */
- while ((prod_ptr != cons_ptr) && (len > 0)) {
- int xx;
-
- /* Get 4 bytes (one ring entry) at a time */
- entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
-
- /* Invalidate all entries */
- entry->ring_allsc = 0;
-
- /* Copy in some bytes */
- for (xx = 0; (xx < 4) && (len > 0); xx++) {
- entry->ring_data[xx] = *buf++;
- entry->ring_sc[xx] = IOC4_TXCB_VALID;
- len--;
- total++;
- }
-
- /* If we are within some small threshold of filling up the
- * entire ring buffer, we must place an EXPLICIT intr here
- * to generate a lowat interrupt in case we subsequently
- * really do fill up the ring and the caller goes to sleep.
- * No need to place more than one though.
- */
- if (!(port->ip_flags & LOWAT_WRITTEN) &&
- ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
- <= port->ip_tx_lowat
- * (int)sizeof(struct ring_entry)) {
- port->ip_flags |= LOWAT_WRITTEN;
- entry->ring_sc[0] |= IOC4_TXCB_INT_WHEN_DONE;
- }
-
- /* Go on to next entry */
- prod_ptr += sizeof(struct ring_entry);
- prod_ptr &= PROD_CONS_MASK;
- }
-
- /* If we sent something, start DMA if necessary */
- if (total > 0 && !(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
- port->ip_sscr |= IOC4_SSCR_DMA_EN;
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
-
- /* Store the new producer pointer. If tx is disabled, we stuff the
- * data into the ring buffer, but we don't actually start tx.
- */
- if (!uart_tx_stopped(port->ip_port)) {
- writel(prod_ptr, &port->ip_serial_regs->stpir);
-
- /* If we are now transmitting, enable tx_mt interrupt so we
- * can disable DMA if necessary when the tx finishes.
- */
- if (total > 0)
- enable_intrs(port, hooks->intr_tx_mt);
- }
- port->ip_tx_prod = prod_ptr;
- return total;
-}
-
-/**
- * disable_intrs - disable interrupts
- * @port: port to enable
- * @mask: mask to use
- */
-static void disable_intrs(struct ioc4_port *port, uint32_t mask)
-{
- struct hooks *hooks = port->ip_hooks;
-
- if (port->ip_ienb & mask) {
- write_ireg(port->ip_ioc4_soft, mask, IOC4_W_IEC,
- IOC4_SIO_INTR_TYPE);
- port->ip_ienb &= ~mask;
- }
-
- if (!port->ip_ienb)
- write_ireg(port->ip_ioc4_soft, hooks->intr_dma_error,
- IOC4_W_IEC, IOC4_OTHER_INTR_TYPE);
-}
-
-/**
- * set_notification - Modify event notification
- * @port: port to use
- * @mask: events mask
- * @set_on: set ?
- */
-static int set_notification(struct ioc4_port *port, int mask, int set_on)
-{
- struct hooks *hooks = port->ip_hooks;
- uint32_t intrbits, sscrbits;
-
- BUG_ON(!mask);
-
- intrbits = sscrbits = 0;
-
- if (mask & N_DATA_READY)
- intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
- if (mask & N_OUTPUT_LOWAT)
- intrbits |= hooks->intr_tx_explicit;
- if (mask & N_DDCD) {
- intrbits |= hooks->intr_delta_dcd;
- sscrbits |= IOC4_SSCR_RX_RING_DCD;
- }
- if (mask & N_DCTS)
- intrbits |= hooks->intr_delta_cts;
-
- if (set_on) {
- enable_intrs(port, intrbits);
- port->ip_notify |= mask;
- port->ip_sscr |= sscrbits;
- } else {
- disable_intrs(port, intrbits);
- port->ip_notify &= ~mask;
- port->ip_sscr &= ~sscrbits;
- }
-
- /* We require DMA if either DATA_READY or DDCD notification is
- * currently requested. If neither of these is requested and
- * there is currently no tx in progress, DMA may be disabled.
- */
- if (port->ip_notify & (N_DATA_READY | N_DDCD))
- port->ip_sscr |= IOC4_SSCR_DMA_EN;
- else if (!(port->ip_ienb & hooks->intr_tx_mt))
- port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
-
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- return 0;
-}
-
-/**
- * set_mcr - set the master control reg
- * @the_port: port to use
- * @mask1: mcr mask
- * @mask2: shadow mask
- */
-static inline int set_mcr(struct uart_port *the_port,
- int mask1, int mask2)
-{
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
- uint32_t shadow;
- int spiniter = 0;
- char mcr;
-
- if (!port)
- return -1;
-
- /* Pause the DMA interface if necessary */
- if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
- writel(port->ip_sscr | IOC4_SSCR_DMA_PAUSE,
- &port->ip_serial_regs->sscr);
- while ((readl(&port->ip_serial_regs->sscr)
- & IOC4_SSCR_PAUSE_STATE) == 0) {
- spiniter++;
- if (spiniter > MAXITER)
- return -1;
- }
- }
- shadow = readl(&port->ip_serial_regs->shadow);
- mcr = (shadow & 0xff000000) >> 24;
-
- /* Set new value */
- mcr |= mask1;
- shadow |= mask2;
-
- writeb(mcr, &port->ip_uart_regs->i4u_mcr);
- writel(shadow, &port->ip_serial_regs->shadow);
-
- /* Re-enable the DMA interface if necessary */
- if (port->ip_sscr & IOC4_SSCR_DMA_EN) {
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
- return 0;
-}
-
-/**
- * ioc4_set_proto - set the protocol for the port
- * @port: port to use
- * @proto: protocol to use
- */
-static int ioc4_set_proto(struct ioc4_port *port, int proto)
-{
- struct hooks *hooks = port->ip_hooks;
-
- switch (proto) {
- case PROTO_RS232:
- /* Clear the appropriate GIO pin */
- writel(0, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
- break;
-
- case PROTO_RS422:
- /* Set the appropriate GIO pin */
- writel(1, (&port->ip_mem->gppr[hooks->rs422_select_pin].raw));
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
-/**
- * transmit_chars - upper level write, called with ip_lock
- * @the_port: port to write
- */
-static void transmit_chars(struct uart_port *the_port)
-{
- int xmit_count, tail, head;
- int result;
- char *start;
- struct tty_struct *tty;
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
- struct uart_state *state;
-
- if (!the_port)
- return;
- if (!port)
- return;
-
- state = the_port->state;
- tty = state->port.tty;
-
- if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) {
- /* Nothing to do or hw stopped */
- set_notification(port, N_ALL_OUTPUT, 0);
- return;
- }
-
- head = state->xmit.head;
- tail = state->xmit.tail;
- start = (char *)&state->xmit.buf[tail];
-
- /* write out all the data or until the end of the buffer */
- xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
- if (xmit_count > 0) {
- result = do_write(port, start, xmit_count);
- if (result > 0) {
- /* booking */
- xmit_count -= result;
- the_port->icount.tx += result;
- /* advance the pointers */
- tail += result;
- tail &= UART_XMIT_SIZE - 1;
- state->xmit.tail = tail;
- start = (char *)&state->xmit.buf[tail];
- }
- }
- if (uart_circ_chars_pending(&state->xmit) < WAKEUP_CHARS)
- uart_write_wakeup(the_port);
-
- if (uart_circ_empty(&state->xmit)) {
- set_notification(port, N_OUTPUT_LOWAT, 0);
- } else {
- set_notification(port, N_OUTPUT_LOWAT, 1);
- }
-}
-
-/**
- * ioc4_change_speed - change the speed of the port
- * @the_port: port to change
- * @new_termios: new termios settings
- * @old_termios: old termios settings
- */
-static void
-ioc4_change_speed(struct uart_port *the_port,
- struct ktermios *new_termios, struct ktermios *old_termios)
-{
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
- int baud, bits;
- unsigned cflag, iflag;
- int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
- struct uart_state *state = the_port->state;
-
- cflag = new_termios->c_cflag;
- iflag = new_termios->c_iflag;
-
- switch (cflag & CSIZE) {
- case CS5:
- new_data = 5;
- bits = 7;
- break;
- case CS6:
- new_data = 6;
- bits = 8;
- break;
- case CS7:
- new_data = 7;
- bits = 9;
- break;
- case CS8:
- new_data = 8;
- bits = 10;
- break;
- default:
- /* cuz we always need a default ... */
- new_data = 5;
- bits = 7;
- break;
- }
- if (cflag & CSTOPB) {
- bits++;
- new_stop = 1;
- }
- if (cflag & PARENB) {
- bits++;
- new_parity_enable = 1;
- if (cflag & PARODD)
- new_parity = 1;
- }
- baud = uart_get_baud_rate(the_port, new_termios, old_termios,
- MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
-
- /* default is 9600 */
- if (!baud)
- baud = 9600;
-
- if (!the_port->fifosize)
- the_port->fifosize = IOC4_FIFO_CHARS;
- the_port->timeout = ((the_port->fifosize * HZ * bits) / (baud / 10));
- the_port->timeout += HZ / 50; /* Add .02 seconds of slop */
-
- the_port->ignore_status_mask = N_ALL_INPUT;
-
- state->port.low_latency = 1;
-
- if (iflag & IGNPAR)
- the_port->ignore_status_mask &= ~(N_PARITY_ERROR
- | N_FRAMING_ERROR);
- if (iflag & IGNBRK) {
- the_port->ignore_status_mask &= ~N_BREAK;
- if (iflag & IGNPAR)
- the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
- }
- if (!(cflag & CREAD)) {
- /* ignore everything */
- the_port->ignore_status_mask &= ~N_DATA_READY;
- }
-
- if (cflag & CRTSCTS) {
- port->ip_sscr |= IOC4_SSCR_HFC_EN;
- }
- else {
- port->ip_sscr &= ~IOC4_SSCR_HFC_EN;
- }
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
-
- /* Set the configuration and proper notification call */
- DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
- "config_port(baud %d data %d stop %d p enable %d parity %d),"
- " notification 0x%x\n",
- __func__, (void *)port, cflag, baud, new_data, new_stop,
- new_parity_enable, new_parity, the_port->ignore_status_mask));
-
- if ((config_port(port, baud, /* baud */
- new_data, /* byte size */
- new_stop, /* stop bits */
- new_parity_enable, /* set parity */
- new_parity)) >= 0) { /* parity 1==odd */
- set_notification(port, the_port->ignore_status_mask, 1);
- }
-}
-
-/**
- * ic4_startup_local - Start up the serial port - returns >= 0 if no errors
- * @the_port: Port to operate on
- */
-static inline int ic4_startup_local(struct uart_port *the_port)
-{
- struct ioc4_port *port;
- struct uart_state *state;
-
- if (!the_port)
- return -1;
-
- port = get_ioc4_port(the_port, 0);
- if (!port)
- return -1;
-
- state = the_port->state;
-
- local_open(port);
-
- /* set the protocol - mapbase has the port type */
- ioc4_set_proto(port, the_port->mapbase);
-
- /* set the speed of the serial port */
- ioc4_change_speed(the_port, &state->port.tty->termios,
- (struct ktermios *)0);
-
- return 0;
-}
-
-/*
- * ioc4_cb_output_lowat - called when the output low water mark is hit
- * @the_port: port to output
- */
-static void ioc4_cb_output_lowat(struct uart_port *the_port)
-{
- unsigned long pflags;
-
- /* ip_lock is set on the call here */
- if (the_port) {
- spin_lock_irqsave(&the_port->lock, pflags);
- transmit_chars(the_port);
- spin_unlock_irqrestore(&the_port->lock, pflags);
- }
-}
-
-/**
- * handle_intr - service any interrupts for the given port - 2nd level
- * called via sd_intr
- * @arg: handler arg
- * @sio_ir: ioc4regs
- */
-static void handle_intr(void *arg, uint32_t sio_ir)
-{
- struct ioc4_port *port = (struct ioc4_port *)arg;
- struct hooks *hooks = port->ip_hooks;
- unsigned int rx_high_rd_aborted = 0;
- unsigned long flags;
- struct uart_port *the_port;
- int loop_counter;
-
- /* Possible race condition here: The tx_mt interrupt bit may be
- * cleared without the intervention of the interrupt handler,
- * e.g. by a write. If the top level interrupt handler reads a
- * tx_mt, then some other processor does a write, starting up
- * output, then we come in here, see the tx_mt and stop DMA, the
- * output started by the other processor will hang. Thus we can
- * only rely on tx_mt being legitimate if it is read while the
- * port lock is held. Therefore this bit must be ignored in the
- * passed in interrupt mask which was read by the top level
- * interrupt handler since the port lock was not held at the time
- * it was read. We can only rely on this bit being accurate if it
- * is read while the port lock is held. So we'll clear it for now,
- * and reload it later once we have the port lock.
- */
- sio_ir &= ~(hooks->intr_tx_mt);
-
- spin_lock_irqsave(&port->ip_lock, flags);
-
- loop_counter = MAXITER; /* to avoid hangs */
-
- do {
- uint32_t shadow;
-
- if ( loop_counter-- <= 0 ) {
- printk(KERN_WARNING "IOC4 serial: "
- "possible hang condition/"
- "port stuck on interrupt.\n");
- break;
- }
-
- /* Handle a DCD change */
- if (sio_ir & hooks->intr_delta_dcd) {
- /* ACK the interrupt */
- writel(hooks->intr_delta_dcd,
- &port->ip_mem->sio_ir.raw);
-
- shadow = readl(&port->ip_serial_regs->shadow);
-
- if ((port->ip_notify & N_DDCD)
- && (shadow & IOC4_SHADOW_DCD)
- && (port->ip_port)) {
- the_port = port->ip_port;
- the_port->icount.dcd = 1;
- wake_up_interruptible
- (&the_port->state->port.delta_msr_wait);
- } else if ((port->ip_notify & N_DDCD)
- && !(shadow & IOC4_SHADOW_DCD)) {
- /* Flag delta DCD/no DCD */
- port->ip_flags |= DCD_ON;
- }
- }
-
- /* Handle a CTS change */
- if (sio_ir & hooks->intr_delta_cts) {
- /* ACK the interrupt */
- writel(hooks->intr_delta_cts,
- &port->ip_mem->sio_ir.raw);
-
- shadow = readl(&port->ip_serial_regs->shadow);
-
- if ((port->ip_notify & N_DCTS)
- && (port->ip_port)) {
- the_port = port->ip_port;
- the_port->icount.cts =
- (shadow & IOC4_SHADOW_CTS) ? 1 : 0;
- wake_up_interruptible
- (&the_port->state->port.delta_msr_wait);
- }
- }
-
- /* rx timeout interrupt. Must be some data available. Put this
- * before the check for rx_high since servicing this condition
- * may cause that condition to clear.
- */
- if (sio_ir & hooks->intr_rx_timer) {
- /* ACK the interrupt */
- writel(hooks->intr_rx_timer,
- &port->ip_mem->sio_ir.raw);
-
- if ((port->ip_notify & N_DATA_READY)
- && (port->ip_port)) {
- /* ip_lock is set on call here */
- receive_chars(port->ip_port);
- }
- }
-
- /* rx high interrupt. Must be after rx_timer. */
- else if (sio_ir & hooks->intr_rx_high) {
- /* Data available, notify upper layer */
- if ((port->ip_notify & N_DATA_READY)
- && port->ip_port) {
- /* ip_lock is set on call here */
- receive_chars(port->ip_port);
- }
-
- /* We can't ACK this interrupt. If receive_chars didn't
- * cause the condition to clear, we'll have to disable
- * the interrupt until the data is drained.
- * If the read was aborted, don't disable the interrupt
- * as this may cause us to hang indefinitely. An
- * aborted read generally means that this interrupt
- * hasn't been delivered to the cpu yet anyway, even
- * though we see it as asserted when we read the sio_ir.
- */
- if ((sio_ir = PENDING(port)) & hooks->intr_rx_high) {
- if ((port->ip_flags & READ_ABORTED) == 0) {
- port->ip_ienb &= ~hooks->intr_rx_high;
- port->ip_flags |= INPUT_HIGH;
- } else {
- rx_high_rd_aborted++;
- }
- }
- }
-
- /* We got a low water interrupt: notify upper layer to
- * send more data. Must come before tx_mt since servicing
- * this condition may cause that condition to clear.
- */
- if (sio_ir & hooks->intr_tx_explicit) {
- port->ip_flags &= ~LOWAT_WRITTEN;
-
- /* ACK the interrupt */
- writel(hooks->intr_tx_explicit,
- &port->ip_mem->sio_ir.raw);
-
- if (port->ip_notify & N_OUTPUT_LOWAT)
- ioc4_cb_output_lowat(port->ip_port);
- }
-
- /* Handle tx_mt. Must come after tx_explicit. */
- else if (sio_ir & hooks->intr_tx_mt) {
- /* If we are expecting a lowat notification
- * and we get to this point it probably means that for
- * some reason the tx_explicit didn't work as expected
- * (that can legitimately happen if the output buffer is
- * filled up in just the right way).
- * So send the notification now.
- */
- if (port->ip_notify & N_OUTPUT_LOWAT) {
- ioc4_cb_output_lowat(port->ip_port);
-
- /* We need to reload the sio_ir since the lowat
- * call may have caused another write to occur,
- * clearing the tx_mt condition.
- */
- sio_ir = PENDING(port);
- }
-
- /* If the tx_mt condition still persists even after the
- * lowat call, we've got some work to do.
- */
- if (sio_ir & hooks->intr_tx_mt) {
-
- /* If we are not currently expecting DMA input,
- * and the transmitter has just gone idle,
- * there is no longer any reason for DMA, so
- * disable it.
- */
- if (!(port->ip_notify
- & (N_DATA_READY | N_DDCD))) {
- BUG_ON(!(port->ip_sscr
- & IOC4_SSCR_DMA_EN));
- port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
- writel(port->ip_sscr,
- &port->ip_serial_regs->sscr);
- }
-
- /* Prevent infinite tx_mt interrupt */
- port->ip_ienb &= ~hooks->intr_tx_mt;
- }
- }
- sio_ir = PENDING(port);
-
- /* if the read was aborted and only hooks->intr_rx_high,
- * clear hooks->intr_rx_high, so we do not loop forever.
- */
-
- if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
- sio_ir &= ~hooks->intr_rx_high;
- }
- } while (sio_ir & hooks->intr_all);
-
- spin_unlock_irqrestore(&port->ip_lock, flags);
-
- /* Re-enable interrupts before returning from interrupt handler.
- * Getting interrupted here is okay. It'll just v() our semaphore, and
- * we'll come through the loop again.
- */
-
- write_ireg(port->ip_ioc4_soft, port->ip_ienb, IOC4_W_IES,
- IOC4_SIO_INTR_TYPE);
-}
-
-/*
- * ioc4_cb_post_ncs - called for some basic errors
- * @port: port to use
- * @ncs: event
- */
-static void ioc4_cb_post_ncs(struct uart_port *the_port, int ncs)
-{
- struct uart_icount *icount;
-
- icount = &the_port->icount;
-
- if (ncs & NCS_BREAK)
- icount->brk++;
- if (ncs & NCS_FRAMING)
- icount->frame++;
- if (ncs & NCS_OVERRUN)
- icount->overrun++;
- if (ncs & NCS_PARITY)
- icount->parity++;
-}
-
-/**
- * do_read - Read in bytes from the port. Return the number of bytes
- * actually read.
- * @the_port: port to use
- * @buf: place to put the stuff we read
- * @len: how big 'buf' is
- */
-
-static inline int do_read(struct uart_port *the_port, unsigned char *buf,
- int len)
-{
- int prod_ptr, cons_ptr, total;
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
- struct ring *inring;
- struct ring_entry *entry;
- struct hooks *hooks;
- int byte_num;
- char *sc;
- int loop_counter;
-
- BUG_ON(!(len >= 0));
- BUG_ON(!port);
- hooks = port->ip_hooks;
-
- /* There is a nasty timing issue in the IOC4. When the rx_timer
- * expires or the rx_high condition arises, we take an interrupt.
- * At some point while servicing the interrupt, we read bytes from
- * the ring buffer and re-arm the rx_timer. However the rx_timer is
- * not started until the first byte is received *after* it is armed,
- * and any bytes pending in the rx construction buffers are not drained
- * to memory until either there are 4 bytes available or the rx_timer
- * expires. This leads to a potential situation where data is left
- * in the construction buffers forever - 1 to 3 bytes were received
- * after the interrupt was generated but before the rx_timer was
- * re-armed. At that point as long as no subsequent bytes are received
- * the timer will never be started and the bytes will remain in the
- * construction buffer forever. The solution is to execute a DRAIN
- * command after rearming the timer. This way any bytes received before
- * the DRAIN will be drained to memory, and any bytes received after
- * the DRAIN will start the TIMER and be drained when it expires.
- * Luckily, this only needs to be done when the DMA buffer is empty
- * since there is no requirement that this function return all
- * available data as long as it returns some.
- */
- /* Re-arm the timer */
- writel(port->ip_rx_cons | IOC4_SRCIR_ARM, &port->ip_serial_regs->srcir);
-
- prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
- cons_ptr = port->ip_rx_cons;
-
- if (prod_ptr == cons_ptr) {
- int reset_dma = 0;
-
- /* Input buffer appears empty, do a flush. */
-
- /* DMA must be enabled for this to work. */
- if (!(port->ip_sscr & IOC4_SSCR_DMA_EN)) {
- port->ip_sscr |= IOC4_SSCR_DMA_EN;
- reset_dma = 1;
- }
-
- /* Potential race condition: we must reload the srpir after
- * issuing the drain command, otherwise we could think the rx
- * buffer is empty, then take a very long interrupt, and when
- * we come back it's full and we wait forever for the drain to
- * complete.
- */
- writel(port->ip_sscr | IOC4_SSCR_RX_DRAIN,
- &port->ip_serial_regs->sscr);
- prod_ptr = readl(&port->ip_serial_regs->srpir)
- & PROD_CONS_MASK;
-
- /* We must not wait for the DRAIN to complete unless there are
- * at least 8 bytes (2 ring entries) available to receive the
- * data otherwise the DRAIN will never complete and we'll
- * deadlock here.
- * In fact, to make things easier, I'll just ignore the flush if
- * there is any data at all now available.
- */
- if (prod_ptr == cons_ptr) {
- loop_counter = 0;
- while (readl(&port->ip_serial_regs->sscr) &
- IOC4_SSCR_RX_DRAIN) {
- loop_counter++;
- if (loop_counter > MAXITER)
- return -1;
- }
-
- /* SIGH. We have to reload the prod_ptr *again* since
- * the drain may have caused it to change
- */
- prod_ptr = readl(&port->ip_serial_regs->srpir)
- & PROD_CONS_MASK;
- }
- if (reset_dma) {
- port->ip_sscr &= ~IOC4_SSCR_DMA_EN;
- writel(port->ip_sscr, &port->ip_serial_regs->sscr);
- }
- }
- inring = port->ip_inring;
- port->ip_flags &= ~READ_ABORTED;
-
- total = 0;
- loop_counter = 0xfffff; /* to avoid hangs */
-
- /* Grab bytes from the hardware */
- while ((prod_ptr != cons_ptr) && (len > 0)) {
- entry = (struct ring_entry *)((caddr_t)inring + cons_ptr);
-
- if ( loop_counter-- <= 0 ) {
- printk(KERN_WARNING "IOC4 serial: "
- "possible hang condition/"
- "port stuck on read.\n");
- break;
- }
-
- /* According to the producer pointer, this ring entry
- * must contain some data. But if the PIO happened faster
- * than the DMA, the data may not be available yet, so let's
- * wait until it arrives.
- */
- if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
- /* Indicate the read is aborted so we don't disable
- * the interrupt thinking that the consumer is
- * congested.
- */
- port->ip_flags |= READ_ABORTED;
- len = 0;
- break;
- }
-
- /* Load the bytes/status out of the ring entry */
- for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
- sc = &(entry->ring_sc[byte_num]);
-
- /* Check for change in modem state or overrun */
- if ((*sc & IOC4_RXSB_MODEM_VALID)
- && (port->ip_notify & N_DDCD)) {
- /* Notify upper layer if DCD dropped */
-
- if ((port->ip_flags & DCD_ON)
- && !(*sc & IOC4_RXSB_DCD)) {
-
- /* If we have already copied some data,
- * return it. We'll pick up the carrier
- * drop on the next pass. That way we
- * don't throw away the data that has
- * already been copied back to
- * the caller's buffer.
- */
- if (total > 0) {
- len = 0;
- break;
- }
- port->ip_flags &= ~DCD_ON;
-
- /* Turn off this notification so the
- * carrier drop protocol won't see it
- * again when it does a read.
- */
- *sc &= ~IOC4_RXSB_MODEM_VALID;
-
- /* To keep things consistent, we need
- * to update the consumer pointer so
- * the next reader won't come in and
- * try to read the same ring entries
- * again. This must be done here before
- * the dcd change.
- */
-
- if ((entry->ring_allsc & RING_ANY_VALID)
- == 0) {
- cons_ptr += (int)sizeof
- (struct ring_entry);
- cons_ptr &= PROD_CONS_MASK;
- }
- writel(cons_ptr,
- &port->ip_serial_regs->srcir);
- port->ip_rx_cons = cons_ptr;
-
- /* Notify upper layer of carrier drop */
- if ((port->ip_notify & N_DDCD)
- && port->ip_port) {
- the_port->icount.dcd = 0;
- wake_up_interruptible
- (&the_port->state->
- port.delta_msr_wait);
- }
-
- /* If we had any data to return, we
- * would have returned it above.
- */
- return 0;
- }
- }
- if (*sc & IOC4_RXSB_MODEM_VALID) {
- /* Notify that an input overrun occurred */
- if ((*sc & IOC4_RXSB_OVERRUN)
- && (port->ip_notify & N_OVERRUN_ERROR)) {
- ioc4_cb_post_ncs(the_port, NCS_OVERRUN);
- }
- /* Don't look at this byte again */
- *sc &= ~IOC4_RXSB_MODEM_VALID;
- }
-
- /* Check for valid data or RX errors */
- if ((*sc & IOC4_RXSB_DATA_VALID) &&
- ((*sc & (IOC4_RXSB_PAR_ERR
- | IOC4_RXSB_FRAME_ERR
- | IOC4_RXSB_BREAK))
- && (port->ip_notify & (N_PARITY_ERROR
- | N_FRAMING_ERROR
- | N_BREAK)))) {
- /* There is an error condition on the next byte.
- * If we have already transferred some bytes,
- * we'll stop here. Otherwise if this is the
- * first byte to be read, we'll just transfer
- * it alone after notifying the
- * upper layer of its status.
- */
- if (total > 0) {
- len = 0;
- break;
- } else {
- if ((*sc & IOC4_RXSB_PAR_ERR) &&
- (port->ip_notify & N_PARITY_ERROR)) {
- ioc4_cb_post_ncs(the_port,
- NCS_PARITY);
- }
- if ((*sc & IOC4_RXSB_FRAME_ERR) &&
- (port->ip_notify & N_FRAMING_ERROR)){
- ioc4_cb_post_ncs(the_port,
- NCS_FRAMING);
- }
- if ((*sc & IOC4_RXSB_BREAK)
- && (port->ip_notify & N_BREAK)) {
- ioc4_cb_post_ncs
- (the_port,
- NCS_BREAK);
- }
- len = 1;
- }
- }
- if (*sc & IOC4_RXSB_DATA_VALID) {
- *sc &= ~IOC4_RXSB_DATA_VALID;
- *buf = entry->ring_data[byte_num];
- buf++;
- len--;
- total++;
- }
- }
-
- /* If we used up this entry entirely, go on to the next one,
- * otherwise we must have run out of buffer space, so
- * leave the consumer pointer here for the next read in case
- * there are still unread bytes in this entry.
- */
- if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
- cons_ptr += (int)sizeof(struct ring_entry);
- cons_ptr &= PROD_CONS_MASK;
- }
- }
-
- /* Update consumer pointer and re-arm rx timer interrupt */
- writel(cons_ptr, &port->ip_serial_regs->srcir);
- port->ip_rx_cons = cons_ptr;
-
- /* If we have now dipped below the rx high water mark and we have
- * rx_high interrupt turned off, we can now turn it back on again.
- */
- if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
- & PROD_CONS_MASK) < ((port->ip_sscr &
- IOC4_SSCR_RX_THRESHOLD)
- << IOC4_PROD_CONS_PTR_OFF))) {
- port->ip_flags &= ~INPUT_HIGH;
- enable_intrs(port, hooks->intr_rx_high);
- }
- return total;
-}
-
-/**
- * receive_chars - upper level read. Called with ip_lock.
- * @the_port: port to read from
- */
-static void receive_chars(struct uart_port *the_port)
-{
- unsigned char ch[IOC4_MAX_CHARS];
- int read_count, request_count = IOC4_MAX_CHARS;
- struct uart_icount *icount;
- struct uart_state *state = the_port->state;
- unsigned long pflags;
-
- /* Make sure all the pointers are "good" ones */
- if (!state)
- return;
-
- spin_lock_irqsave(&the_port->lock, pflags);
-
- request_count = tty_buffer_request_room(&state->port, IOC4_MAX_CHARS);
-
- if (request_count > 0) {
- icount = &the_port->icount;
- read_count = do_read(the_port, ch, request_count);
- if (read_count > 0) {
- tty_insert_flip_string(&state->port, ch, read_count);
- icount->rx += read_count;
- }
- }
-
- spin_unlock_irqrestore(&the_port->lock, pflags);
-
- tty_flip_buffer_push(&state->port);
-}
-
-/**
- * ic4_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *ic4_type(struct uart_port *the_port)
-{
- if (the_port->mapbase == PROTO_RS232)
- return "SGI IOC4 Serial [rs232]";
- else
- return "SGI IOC4 Serial [rs422]";
-}
-
-/**
- * ic4_tx_empty - Is the transmitter empty?
- * @port: Port to operate on
- *
- */
-static unsigned int ic4_tx_empty(struct uart_port *the_port)
-{
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
- unsigned int ret = 0;
-
- if (port_is_active(port, the_port)) {
- if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT)
- ret = TIOCSER_TEMT;
- }
- return ret;
-}
-
-/**
- * ic4_stop_tx - stop the transmitter
- * @port: Port to operate on
- *
- */
-static void ic4_stop_tx(struct uart_port *the_port)
-{
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
- if (port_is_active(port, the_port))
- set_notification(port, N_OUTPUT_LOWAT, 0);
-}
-
-/**
- * null_void_function -
- * @port: Port to operate on
- *
- */
-static void null_void_function(struct uart_port *the_port)
-{
-}
-
-/**
- * ic4_shutdown - shut down the port - free irq and disable
- * @port: Port to shut down
- *
- */
-static void ic4_shutdown(struct uart_port *the_port)
-{
- unsigned long port_flags;
- struct ioc4_port *port;
- struct uart_state *state;
-
- port = get_ioc4_port(the_port, 0);
- if (!port)
- return;
-
- state = the_port->state;
- port->ip_port = NULL;
-
- wake_up_interruptible(&state->port.delta_msr_wait);
-
- if (state->port.tty)
- set_bit(TTY_IO_ERROR, &state->port.tty->flags);
-
- spin_lock_irqsave(&the_port->lock, port_flags);
- set_notification(port, N_ALL, 0);
- port->ip_flags = PORT_INACTIVE;
- spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_set_mctrl - set control lines (dtr, rts, etc)
- * @port: Port to operate on
- * @mctrl: Lines to set/unset
- *
- */
-static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
-{
- unsigned char mcr = 0;
- struct ioc4_port *port;
-
- port = get_ioc4_port(the_port, 0);
- if (!port_is_active(port, the_port))
- return;
-
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
-
- set_mcr(the_port, mcr, IOC4_SHADOW_DTR);
-}
-
-/**
- * ic4_get_mctrl - get control line info
- * @port: port to operate on
- *
- */
-static unsigned int ic4_get_mctrl(struct uart_port *the_port)
-{
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
- uint32_t shadow;
- unsigned int ret = 0;
-
- if (!port_is_active(port, the_port))
- return 0;
-
- shadow = readl(&port->ip_serial_regs->shadow);
- if (shadow & IOC4_SHADOW_DCD)
- ret |= TIOCM_CAR;
- if (shadow & IOC4_SHADOW_DR)
- ret |= TIOCM_DSR;
- if (shadow & IOC4_SHADOW_CTS)
- ret |= TIOCM_CTS;
- return ret;
-}
-
-/**
- * ic4_start_tx - Start transmitter, flush any output
- * @port: Port to operate on
- *
- */
-static void ic4_start_tx(struct uart_port *the_port)
-{
- struct ioc4_port *port = get_ioc4_port(the_port, 0);
-
- if (port_is_active(port, the_port)) {
- set_notification(port, N_OUTPUT_LOWAT, 1);
- enable_intrs(port, port->ip_hooks->intr_tx_mt);
- }
-}
-
-/**
- * ic4_break_ctl - handle breaks
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void ic4_break_ctl(struct uart_port *the_port, int break_state)
-{
-}
-
-/**
- * ic4_startup - Start up the serial port
- * @port: Port to operate on
- *
- */
-static int ic4_startup(struct uart_port *the_port)
-{
- int retval;
- struct ioc4_port *port;
- struct ioc4_control *control;
- struct uart_state *state;
- unsigned long port_flags;
-
- if (!the_port)
- return -ENODEV;
- port = get_ioc4_port(the_port, 1);
- if (!port)
- return -ENODEV;
- state = the_port->state;
-
- control = port->ip_control;
- if (!control) {
- port->ip_port = NULL;
- return -ENODEV;
- }
-
- /* Start up the serial port */
- spin_lock_irqsave(&the_port->lock, port_flags);
- retval = ic4_startup_local(the_port);
- spin_unlock_irqrestore(&the_port->lock, port_flags);
- return retval;
-}
-
-/**
- * ic4_set_termios - set termios stuff
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-ic4_set_termios(struct uart_port *the_port,
- struct ktermios *termios, struct ktermios *old_termios)
-{
- unsigned long port_flags;
-
- spin_lock_irqsave(&the_port->lock, port_flags);
- ioc4_change_speed(the_port, termios, old_termios);
- spin_unlock_irqrestore(&the_port->lock, port_flags);
-}
-
-/**
- * ic4_request_port - allocate resources for port - no op....
- * @port: port to operate on
- *
- */
-static int ic4_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static const struct uart_ops ioc4_ops = {
- .tx_empty = ic4_tx_empty,
- .set_mctrl = ic4_set_mctrl,
- .get_mctrl = ic4_get_mctrl,
- .stop_tx = ic4_stop_tx,
- .start_tx = ic4_start_tx,
- .stop_rx = null_void_function,
- .break_ctl = ic4_break_ctl,
- .startup = ic4_startup,
- .shutdown = ic4_shutdown,
- .set_termios = ic4_set_termios,
- .type = ic4_type,
- .release_port = null_void_function,
- .request_port = ic4_request_port,
-};
-
-/*
- * Boot-time initialization code
- */
-
-static struct uart_driver ioc4_uart_rs232 = {
- .owner = THIS_MODULE,
- .driver_name = "ioc4_serial_rs232",
- .dev_name = DEVICE_NAME_RS232,
- .major = DEVICE_MAJOR,
- .minor = DEVICE_MINOR_RS232,
- .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-static struct uart_driver ioc4_uart_rs422 = {
- .owner = THIS_MODULE,
- .driver_name = "ioc4_serial_rs422",
- .dev_name = DEVICE_NAME_RS422,
- .major = DEVICE_MAJOR,
- .minor = DEVICE_MINOR_RS422,
- .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS,
-};
-
-
-/**
- * ioc4_serial_remove_one - detach function
- *
- * @idd: IOC4 master module data for this IOC4
- */
-
-static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
-{
- int port_num, port_type;
- struct ioc4_control *control;
- struct uart_port *the_port;
- struct ioc4_port *port;
- struct ioc4_soft *soft;
-
- /* If serial driver did not attach, don't try to detach */
- control = idd->idd_serial_data;
- if (!control)
- return 0;
-
- for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
- for (port_type = UART_PORT_MIN;
- port_type < UART_PORT_COUNT;
- port_type++) {
- the_port = &control->ic_port[port_num].icp_uart_port
- [port_type];
- if (the_port) {
- switch (port_type) {
- case UART_PORT_RS422:
- uart_remove_one_port(&ioc4_uart_rs422,
- the_port);
- break;
- default:
- case UART_PORT_RS232:
- uart_remove_one_port(&ioc4_uart_rs232,
- the_port);
- break;
- }
- }
- }
- port = control->ic_port[port_num].icp_port;
- /* we allocate in pairs */
- if (!(port_num & 1) && port) {
- pci_free_consistent(port->ip_pdev,
- TOTAL_RING_BUF_SIZE,
- port->ip_cpu_ringbuf,
- port->ip_dma_ringbuf);
- kfree(port);
- }
- }
- soft = control->ic_soft;
- if (soft) {
- free_irq(control->ic_irq, soft);
- if (soft->is_ioc4_serial_addr) {
- iounmap(soft->is_ioc4_serial_addr);
- release_mem_region((unsigned long)
- soft->is_ioc4_serial_addr,
- sizeof(struct ioc4_serial));
- }
- kfree(soft);
- }
- kfree(control);
- idd->idd_serial_data = NULL;
-
- return 0;
-}
-
-
-/**
- * ioc4_serial_core_attach_rs232 - register with serial core
- * This is done during pci probing
- * @pdev: handle for this card
- */
-static inline int
-ioc4_serial_core_attach(struct pci_dev *pdev, int port_type)
-{
- struct ioc4_port *port;
- struct uart_port *the_port;
- struct ioc4_driver_data *idd = pci_get_drvdata(pdev);
- struct ioc4_control *control = idd->idd_serial_data;
- int port_num;
- int port_type_idx;
- struct uart_driver *u_driver;
-
-
- DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
- __func__, pdev, (void *)control));
-
- if (!control)
- return -ENODEV;
-
- port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232
- : UART_PORT_RS422;
-
- u_driver = (port_type == PROTO_RS232) ? &ioc4_uart_rs232
- : &ioc4_uart_rs422;
-
- /* once around for each port on this card */
- for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) {
- the_port = &control->ic_port[port_num].icp_uart_port
- [port_type_idx];
- port = control->ic_port[port_num].icp_port;
- port->ip_all_ports[port_type_idx] = the_port;
-
- DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
- __func__, (void *)the_port,
- (void *)port,
- port_type == PROTO_RS232 ? "rs232" : "rs422"));
-
- /* membase, iobase and mapbase just need to be non-0 */
- the_port->membase = (unsigned char __iomem *)1;
- the_port->iobase = (pdev->bus->number << 16) | port_num;
- the_port->line = (Num_of_ioc4_cards << 2) | port_num;
- the_port->mapbase = port_type;
- the_port->type = PORT_16550A;
- the_port->fifosize = IOC4_FIFO_CHARS;
- the_port->ops = &ioc4_ops;
- the_port->irq = control->ic_irq;
- the_port->dev = &pdev->dev;
- spin_lock_init(&the_port->lock);
- if (uart_add_one_port(u_driver, the_port) < 0) {
- printk(KERN_WARNING
- "%s: unable to add port %d bus %d\n",
- __func__, the_port->line, pdev->bus->number);
- } else {
- DPRINT_CONFIG(
- ("IOC4 serial port %d irq = %d, bus %d\n",
- the_port->line, the_port->irq, pdev->bus->number));
- }
- }
- return 0;
-}
-
-/**
- * ioc4_serial_attach_one - register attach function
- * called per card found from IOC4 master module.
- * @idd: Master module data for this IOC4
- */
-static int
-ioc4_serial_attach_one(struct ioc4_driver_data *idd)
-{
- unsigned long tmp_addr1;
- struct ioc4_serial __iomem *serial;
- struct ioc4_soft *soft;
- struct ioc4_control *control;
- int ret = 0;
-
-
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
- idd->idd_pci_id));
-
- /* PCI-RT does not bring out serial connections.
- * Do not attach to this particular IOC4.
- */
- if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
- return 0;
-
- /* request serial registers */
- tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
-
- if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
- "sioc4_uart")) {
- printk(KERN_WARNING
- "ioc4 (%p): unable to get request region for "
- "uart space\n", (void *)idd->idd_pdev);
- ret = -ENODEV;
- goto out1;
- }
- serial = ioremap(tmp_addr1, sizeof(struct ioc4_serial));
- if (!serial) {
- printk(KERN_WARNING
- "ioc4 (%p) : unable to remap ioc4 serial register\n",
- (void *)idd->idd_pdev);
- ret = -ENODEV;
- goto out2;
- }
- DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
- __func__, (void *)idd->idd_misc_regs,
- (void *)serial));
-
- /* Get memory for the new card */
- control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
-
- if (!control) {
- printk(KERN_WARNING "ioc4_attach_one"
- ": unable to get memory for the IOC4\n");
- ret = -ENOMEM;
- goto out2;
- }
- idd->idd_serial_data = control;
-
- /* Allocate the soft structure */
- soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
- if (!soft) {
- printk(KERN_WARNING
- "ioc4 (%p): unable to get memory for the soft struct\n",
- (void *)idd->idd_pdev);
- ret = -ENOMEM;
- goto out3;
- }
-
- spin_lock_init(&soft->is_ir_lock);
- soft->is_ioc4_misc_addr = idd->idd_misc_regs;
- soft->is_ioc4_serial_addr = serial;
-
- /* Init the IOC4 */
- writel(0xf << IOC4_SIO_CR_CMD_PULSE_SHIFT,
- &idd->idd_misc_regs->sio_cr.raw);
-
- /* Enable serial port mode select generic PIO pins as outputs */
- writel(IOC4_GPCR_UART0_MODESEL | IOC4_GPCR_UART1_MODESEL
- | IOC4_GPCR_UART2_MODESEL | IOC4_GPCR_UART3_MODESEL,
- &idd->idd_misc_regs->gpcr_s.raw);
-
- /* Clear and disable all serial interrupts */
- write_ireg(soft, ~0, IOC4_W_IEC, IOC4_SIO_INTR_TYPE);
- writel(~0, &idd->idd_misc_regs->sio_ir.raw);
- write_ireg(soft, IOC4_OTHER_IR_SER_MEMERR, IOC4_W_IEC,
- IOC4_OTHER_INTR_TYPE);
- writel(IOC4_OTHER_IR_SER_MEMERR, &idd->idd_misc_regs->other_ir.raw);
- control->ic_soft = soft;
-
- /* Hook up interrupt handler */
- if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
- "sgi-ioc4serial", soft)) {
- control->ic_irq = idd->idd_pdev->irq;
- } else {
- printk(KERN_WARNING
- "%s : request_irq fails for IRQ 0x%x\n ",
- __func__, idd->idd_pdev->irq);
- }
- ret = ioc4_attach_local(idd);
- if (ret)
- goto out4;
-
- /* register port with the serial core - 1 rs232, 1 rs422 */
-
- ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232);
- if (ret)
- goto out4;
-
- ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422);
- if (ret)
- goto out5;
-
- Num_of_ioc4_cards++;
-
- return ret;
-
- /* error exits that give back resources */
-out5:
- ioc4_serial_remove_one(idd);
- return ret;
-out4:
- kfree(soft);
-out3:
- kfree(control);
-out2:
- if (serial)
- iounmap(serial);
- release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
-out1:
-
- return ret;
-}
-
-
-static struct ioc4_submodule ioc4_serial_submodule = {
- .is_name = "IOC4_serial",
- .is_owner = THIS_MODULE,
- .is_probe = ioc4_serial_attach_one,
- .is_remove = ioc4_serial_remove_one,
-};
-
-/**
- * ioc4_serial_init - module init
- */
-static int __init ioc4_serial_init(void)
-{
- int ret;
-
- /* register with serial core */
- if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
- printk(KERN_WARNING
- "%s: Couldn't register rs232 IOC4 serial driver\n",
- __func__);
- goto out;
- }
- if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
- printk(KERN_WARNING
- "%s: Couldn't register rs422 IOC4 serial driver\n",
- __func__);
- goto out_uart_rs232;
- }
-
- /* register with IOC4 main module */
- ret = ioc4_register_submodule(&ioc4_serial_submodule);
- if (ret)
- goto out_uart_rs422;
- return 0;
-
-out_uart_rs422:
- uart_unregister_driver(&ioc4_uart_rs422);
-out_uart_rs232:
- uart_unregister_driver(&ioc4_uart_rs232);
-out:
- return ret;
-}
-
-static void __exit ioc4_serial_exit(void)
-{
- ioc4_unregister_submodule(&ioc4_serial_submodule);
- uart_unregister_driver(&ioc4_uart_rs232);
- uart_unregister_driver(&ioc4_uart_rs422);
-}
-
-late_initcall(ioc4_serial_init); /* Call only after tty init is done */
-module_exit(ioc4_serial_exit);
-
-MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
-MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC4 Base-IO Card");
-MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c
deleted file mode 100644
index 283493358a62..000000000000
--- a/drivers/tty/serial/sn_console.c
+++ /dev/null
@@ -1,1036 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * C-Brick Serial Port (and console) driver for SGI Altix machines.
- *
- * This driver is NOT suitable for talking to the l1-controller for
- * anything other than 'console activities' --- please use the l1
- * driver for that.
- *
- *
- * Copyright (c) 2004-2006 Silicon Graphics, Inc. All Rights Reserved.
- *
- * Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/NoticeExplan
- */
-
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/sysrq.h>
-#include <linux/circ_buf.h>
-#include <linux/serial_reg.h>
-#include <linux/delay.h> /* for mdelay */
-#include <linux/miscdevice.h>
-#include <linux/serial_core.h>
-
-#include <asm/io.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/sn_sal.h>
-
-/* number of characters we can transmit to the SAL console at a time */
-#define SN_SAL_MAX_CHARS 120
-
-/* 64K, when we're asynch, it must be at least printk's LOG_BUF_LEN to
- * avoid losing chars, (always has to be a power of 2) */
-#define SN_SAL_BUFFER_SIZE (64 * (1 << 10))
-
-#define SN_SAL_UART_FIFO_DEPTH 16
-#define SN_SAL_UART_FIFO_SPEED_CPS (9600/10)
-
-/* sn_transmit_chars() calling args */
-#define TRANSMIT_BUFFERED 0
-#define TRANSMIT_RAW 1
-
-/* To use dynamic numbers only and not use the assigned major and minor,
- * define the following.. */
- /* #define USE_DYNAMIC_MINOR 1 *//* use dynamic minor number */
-#define USE_DYNAMIC_MINOR 0 /* Don't rely on misc_register dynamic minor */
-
-/* Device name we're using */
-#define DEVICE_NAME "ttySG"
-#define DEVICE_NAME_DYNAMIC "ttySG0" /* need full name for misc_register */
-/* The major/minor we are using, ignored for USE_DYNAMIC_MINOR */
-#define DEVICE_MAJOR 204
-#define DEVICE_MINOR 40
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static char sysrq_serial_str[] = "\eSYS";
-static char *sysrq_serial_ptr = sysrq_serial_str;
-static unsigned long sysrq_requested;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-/*
- * Port definition - this kinda drives it all
- */
-struct sn_cons_port {
- struct timer_list sc_timer;
- struct uart_port sc_port;
- struct sn_sal_ops {
- int (*sal_puts_raw) (const char *s, int len);
- int (*sal_puts) (const char *s, int len);
- int (*sal_getc) (void);
- int (*sal_input_pending) (void);
- void (*sal_wakeup_transmit) (struct sn_cons_port *, int);
- } *sc_ops;
- unsigned long sc_interrupt_timeout;
- int sc_is_asynch;
-};
-
-static struct sn_cons_port sal_console_port;
-static int sn_process_input;
-
-/* Only used if USE_DYNAMIC_MINOR is set to 1 */
-static struct miscdevice misc; /* used with misc_register for dynamic */
-
-extern void early_sn_setup(void);
-
-#undef DEBUG
-#ifdef DEBUG
-static int sn_debug_printf(const char *fmt, ...);
-#define DPRINTF(x...) sn_debug_printf(x)
-#else
-#define DPRINTF(x...) do { } while (0)
-#endif
-
-/* Prototypes */
-static int snt_hw_puts_raw(const char *, int);
-static int snt_hw_puts_buffered(const char *, int);
-static int snt_poll_getc(void);
-static int snt_poll_input_pending(void);
-static int snt_intr_getc(void);
-static int snt_intr_input_pending(void);
-static void sn_transmit_chars(struct sn_cons_port *, int);
-
-/* A table for polling:
- */
-static struct sn_sal_ops poll_ops = {
- .sal_puts_raw = snt_hw_puts_raw,
- .sal_puts = snt_hw_puts_raw,
- .sal_getc = snt_poll_getc,
- .sal_input_pending = snt_poll_input_pending
-};
-
-/* A table for interrupts enabled */
-static struct sn_sal_ops intr_ops = {
- .sal_puts_raw = snt_hw_puts_raw,
- .sal_puts = snt_hw_puts_buffered,
- .sal_getc = snt_intr_getc,
- .sal_input_pending = snt_intr_input_pending,
- .sal_wakeup_transmit = sn_transmit_chars
-};
-
-/* the console does output in two distinctly different ways:
- * synchronous (raw) and asynchronous (buffered). initially, early_printk
- * does synchronous output. any data written goes directly to the SAL
- * to be output (incidentally, it is internally buffered by the SAL)
- * after interrupts and timers are initialized and available for use,
- * the console init code switches to asynchronous output. this is
- * also the earliest opportunity to begin polling for console input.
- * after console initialization, console output and tty (serial port)
- * output is buffered and sent to the SAL asynchronously (either by
- * timer callback or by UART interrupt) */
-
-/* routines for running the console in polling mode */
-
-/**
- * snt_poll_getc - Get a character from the console in polling mode
- *
- */
-static int snt_poll_getc(void)
-{
- int ch;
-
- ia64_sn_console_getc(&ch);
- return ch;
-}
-
-/**
- * snt_poll_input_pending - Check if any input is waiting - polling mode.
- *
- */
-static int snt_poll_input_pending(void)
-{
- int status, input;
-
- status = ia64_sn_console_check(&input);
- return !status && input;
-}
-
-/* routines for an interrupt driven console (normal) */
-
-/**
- * snt_intr_getc - Get a character from the console, interrupt mode
- *
- */
-static int snt_intr_getc(void)
-{
- return ia64_sn_console_readc();
-}
-
-/**
- * snt_intr_input_pending - Check if input is pending, interrupt mode
- *
- */
-static int snt_intr_input_pending(void)
-{
- return ia64_sn_console_intr_status() & SAL_CONSOLE_INTR_RECV;
-}
-
-/* these functions are polled and interrupt */
-
-/**
- * snt_hw_puts_raw - Send raw string to the console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_raw(const char *s, int len)
-{
- /* this will call the PROM and not return until this is done */
- return ia64_sn_console_putb(s, len);
-}
-
-/**
- * snt_hw_puts_buffered - Send string to console, polled or interrupt mode
- * @s: String
- * @len: Length
- *
- */
-static int snt_hw_puts_buffered(const char *s, int len)
-{
- /* queue data to the PROM */
- return ia64_sn_console_xmit_chars((char *)s, len);
-}
-
-/* uart interface structs
- * These functions are associated with the uart_port that the serial core
- * infrastructure calls.
- *
- * Note: Due to how the console works, many routines are no-ops.
- */
-
-/**
- * snp_type - What type of console are we?
- * @port: Port to operate with (we ignore since we only have one port)
- *
- */
-static const char *snp_type(struct uart_port *port)
-{
- return ("SGI SN L1");
-}
-
-/**
- * snp_tx_empty - Is the transmitter empty? We pretend we're always empty
- * @port: Port to operate on (we ignore since we only have one port)
- *
- */
-static unsigned int snp_tx_empty(struct uart_port *port)
-{
- return 1;
-}
-
-/**
- * snp_stop_tx - stop the transmitter - no-op for us
- * @port: Port to operat eon - we ignore - no-op function
- *
- */
-static void snp_stop_tx(struct uart_port *port)
-{
-}
-
-/**
- * snp_release_port - Free i/o and resources for port - no-op for us
- * @port: Port to operate on - we ignore - no-op function
- *
- */
-static void snp_release_port(struct uart_port *port)
-{
-}
-
-/**
- * snp_shutdown - shut down the port - free irq and disable - no-op for us
- * @port: Port to shut down - we ignore
- *
- */
-static void snp_shutdown(struct uart_port *port)
-{
-}
-
-/**
- * snp_set_mctrl - set control lines (dtr, rts, etc) - no-op for our console
- * @port: Port to operate on - we ignore
- * @mctrl: Lines to set/unset - we ignore
- *
- */
-static void snp_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-/**
- * snp_get_mctrl - get contorl line info, we just return a static value
- * @port: port to operate on - we only have one port so we ignore this
- *
- */
-static unsigned int snp_get_mctrl(struct uart_port *port)
-{
- return TIOCM_CAR | TIOCM_RNG | TIOCM_DSR | TIOCM_CTS;
-}
-
-/**
- * snp_stop_rx - Stop the receiver - we ignor ethis
- * @port: Port to operate on - we ignore
- *
- */
-static void snp_stop_rx(struct uart_port *port)
-{
-}
-
-/**
- * snp_start_tx - Start transmitter
- * @port: Port to operate on
- *
- */
-static void snp_start_tx(struct uart_port *port)
-{
- if (sal_console_port.sc_ops->sal_wakeup_transmit)
- sal_console_port.sc_ops->sal_wakeup_transmit(&sal_console_port,
- TRANSMIT_BUFFERED);
-
-}
-
-/**
- * snp_break_ctl - handle breaks - ignored by us
- * @port: Port to operate on
- * @break_state: Break state
- *
- */
-static void snp_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-/**
- * snp_startup - Start up the serial port - always return 0 (We're always on)
- * @port: Port to operate on
- *
- */
-static int snp_startup(struct uart_port *port)
-{
- return 0;
-}
-
-/**
- * snp_set_termios - set termios stuff - we ignore these
- * @port: port to operate on
- * @termios: New settings
- * @termios: Old
- *
- */
-static void
-snp_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
-{
-}
-
-/**
- * snp_request_port - allocate resources for port - ignored by us
- * @port: port to operate on
- *
- */
-static int snp_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-/**
- * snp_config_port - allocate resources, set up - we ignore, we're always on
- * @port: Port to operate on
- * @flags: flags used for port setup
- *
- */
-static void snp_config_port(struct uart_port *port, int flags)
-{
-}
-
-/* Associate the uart functions above - given to serial core */
-
-static const struct uart_ops sn_console_ops = {
- .tx_empty = snp_tx_empty,
- .set_mctrl = snp_set_mctrl,
- .get_mctrl = snp_get_mctrl,
- .stop_tx = snp_stop_tx,
- .start_tx = snp_start_tx,
- .stop_rx = snp_stop_rx,
- .break_ctl = snp_break_ctl,
- .startup = snp_startup,
- .shutdown = snp_shutdown,
- .set_termios = snp_set_termios,
- .pm = NULL,
- .type = snp_type,
- .release_port = snp_release_port,
- .request_port = snp_request_port,
- .config_port = snp_config_port,
- .verify_port = NULL,
-};
-
-/* End of uart struct functions and defines */
-
-#ifdef DEBUG
-
-/**
- * sn_debug_printf - close to hardware debugging printf
- * @fmt: printf format
- *
- * This is as "close to the metal" as we can get, used when the driver
- * itself may be broken.
- *
- */
-static int sn_debug_printf(const char *fmt, ...)
-{
- static char printk_buf[1024];
- int printed_len;
- va_list args;
-
- va_start(args, fmt);
- printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
-
- if (!sal_console_port.sc_ops) {
- sal_console_port.sc_ops = &poll_ops;
- early_sn_setup();
- }
- sal_console_port.sc_ops->sal_puts_raw(printk_buf, printed_len);
-
- va_end(args);
- return printed_len;
-}
-#endif /* DEBUG */
-
-/*
- * Interrupt handling routines.
- */
-
-/**
- * sn_receive_chars - Grab characters, pass them to tty layer
- * @port: Port to operate on
- * @flags: irq flags
- *
- * Note: If we're not registered with the serial core infrastructure yet,
- * we don't try to send characters to it...
- *
- */
-static void
-sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
-{
- struct tty_port *tport = NULL;
- int ch;
-
- if (!port) {
- printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
- return;
- }
-
- if (!port->sc_ops) {
- printk(KERN_ERR "sn_receive_chars - port->sc_ops NULL so can't receive\n");
- return;
- }
-
- if (port->sc_port.state) {
- /* The serial_core stuffs are initialized, use them */
- tport = &port->sc_port.state->port;
- }
-
- while (port->sc_ops->sal_input_pending()) {
- ch = port->sc_ops->sal_getc();
- if (ch < 0) {
- printk(KERN_ERR "sn_console: An error occurred while "
- "obtaining data from the console (0x%0x)\n", ch);
- break;
- }
-#ifdef CONFIG_MAGIC_SYSRQ
- if (sysrq_requested) {
- unsigned long sysrq_timeout = sysrq_requested + HZ*5;
-
- sysrq_requested = 0;
- if (ch && time_before(jiffies, sysrq_timeout)) {
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
- handle_sysrq(ch);
- spin_lock_irqsave(&port->sc_port.lock, flags);
- /* ignore actual sysrq command char */
- continue;
- }
- }
- if (ch == *sysrq_serial_ptr) {
- if (!(*++sysrq_serial_ptr)) {
- sysrq_requested = jiffies;
- sysrq_serial_ptr = sysrq_serial_str;
- }
- /*
- * ignore the whole sysrq string except for the
- * leading escape
- */
- if (ch != '\e')
- continue;
- }
- else
- sysrq_serial_ptr = sysrq_serial_str;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
- /* record the character to pass up to the tty layer */
- if (tport) {
- if (tty_insert_flip_char(tport, ch, TTY_NORMAL) == 0)
- break;
- }
- port->sc_port.icount.rx++;
- }
-
- if (tport)
- tty_flip_buffer_push(tport);
-}
-
-/**
- * sn_transmit_chars - grab characters from serial core, send off
- * @port: Port to operate on
- * @raw: Transmit raw or buffered
- *
- * Note: If we're early, before we're registered with serial core, the
- * writes are going through sn_sal_console_write because that's how
- * register_console has been set up. We currently could have asynch
- * polls calling this function due to sn_sal_switch_to_asynch but we can
- * ignore them until we register with the serial core stuffs.
- *
- */
-static void sn_transmit_chars(struct sn_cons_port *port, int raw)
-{
- int xmit_count, tail, head, loops, ii;
- int result;
- char *start;
- struct circ_buf *xmit;
-
- if (!port)
- return;
-
- BUG_ON(!port->sc_is_asynch);
-
- if (port->sc_port.state) {
- /* We're initialized, using serial core infrastructure */
- xmit = &port->sc_port.state->xmit;
- } else {
- /* Probably sn_sal_switch_to_asynch has been run but serial core isn't
- * initialized yet. Just return. Writes are going through
- * sn_sal_console_write (due to register_console) at this time.
- */
- return;
- }
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(&port->sc_port)) {
- /* Nothing to do. */
- ia64_sn_console_intr_disable(SAL_CONSOLE_INTR_XMIT);
- return;
- }
-
- head = xmit->head;
- tail = xmit->tail;
- start = &xmit->buf[tail];
-
- /* twice around gets the tail to the end of the buffer and
- * then to the head, if needed */
- loops = (head < tail) ? 2 : 1;
-
- for (ii = 0; ii < loops; ii++) {
- xmit_count = (head < tail) ?
- (UART_XMIT_SIZE - tail) : (head - tail);
-
- if (xmit_count > 0) {
- if (raw == TRANSMIT_RAW)
- result =
- port->sc_ops->sal_puts_raw(start,
- xmit_count);
- else
- result =
- port->sc_ops->sal_puts(start, xmit_count);
-#ifdef DEBUG
- if (!result)
- DPRINTF("`");
-#endif
- if (result > 0) {
- xmit_count -= result;
- port->sc_port.icount.tx += result;
- tail += result;
- tail &= UART_XMIT_SIZE - 1;
- xmit->tail = tail;
- start = &xmit->buf[tail];
- }
- }
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&port->sc_port);
-
- if (uart_circ_empty(xmit))
- snp_stop_tx(&port->sc_port); /* no-op for us */
-}
-
-/**
- * sn_sal_interrupt - Handle console interrupts
- * @irq: irq #, useful for debug statements
- * @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
- *
- */
-static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
-{
- struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
- unsigned long flags;
- int status = ia64_sn_console_intr_status();
-
- if (!port)
- return IRQ_NONE;
-
- spin_lock_irqsave(&port->sc_port.lock, flags);
- if (status & SAL_CONSOLE_INTR_RECV) {
- sn_receive_chars(port, flags);
- }
- if (status & SAL_CONSOLE_INTR_XMIT) {
- sn_transmit_chars(port, TRANSMIT_BUFFERED);
- }
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
- return IRQ_HANDLED;
-}
-
-/**
- * sn_sal_timer_poll - this function handles polled console mode
- * @data: A pointer to our sn_cons_port (which contains the uart port)
- *
- * data is the pointer that init_timer will store for us. This function is
- * associated with init_timer to see if there is any console traffic.
- * Obviously not used in interrupt mode
- *
- */
-static void sn_sal_timer_poll(struct timer_list *t)
-{
- struct sn_cons_port *port = from_timer(port, t, sc_timer);
- unsigned long flags;
-
- if (!port)
- return;
-
- if (!port->sc_port.irq) {
- spin_lock_irqsave(&port->sc_port.lock, flags);
- if (sn_process_input)
- sn_receive_chars(port, flags);
- sn_transmit_chars(port, TRANSMIT_RAW);
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
- mod_timer(&port->sc_timer,
- jiffies + port->sc_interrupt_timeout);
- }
-}
-
-/*
- * Boot-time initialization code
- */
-
-/**
- * sn_sal_switch_to_asynch - Switch to async mode (as opposed to synch)
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * So this is used by sn_sal_serial_console_init (early on, before we're
- * registered with serial core). It's also used by sn_sal_init
- * right after we've registered with serial core. The later only happens
- * if we didn't already come through here via sn_sal_serial_console_init.
- *
- */
-static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port)
-{
- unsigned long flags;
-
- if (!port)
- return;
-
- DPRINTF("sn_console: about to switch to asynchronous console\n");
-
- /* without early_printk, we may be invoked late enough to race
- * with other cpus doing console IO at this point, however
- * console interrupts will never be enabled */
- spin_lock_irqsave(&port->sc_port.lock, flags);
-
- /* early_printk invocation may have done this for us */
- if (!port->sc_ops)
- port->sc_ops = &poll_ops;
-
- /* we can't turn on the console interrupt (as request_irq
- * calls kmalloc, which isn't set up yet), so we rely on a
- * timer to poll for input and push data from the console
- * buffer.
- */
- timer_setup(&port->sc_timer, sn_sal_timer_poll, 0);
-
- if (IS_RUNNING_ON_SIMULATOR())
- port->sc_interrupt_timeout = 6;
- else {
- /* 960cps / 16 char FIFO = 60HZ
- * HZ / (SN_SAL_FIFO_SPEED_CPS / SN_SAL_FIFO_DEPTH) */
- port->sc_interrupt_timeout =
- HZ * SN_SAL_UART_FIFO_DEPTH / SN_SAL_UART_FIFO_SPEED_CPS;
- }
- mod_timer(&port->sc_timer, jiffies + port->sc_interrupt_timeout);
-
- port->sc_is_asynch = 1;
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
-}
-
-/**
- * sn_sal_switch_to_interrupts - Switch to interrupt driven mode
- * @port: Our sn_cons_port (which contains the uart port)
- *
- * In sn_sal_init, after we're registered with serial core and
- * the port is added, this function is called to switch us to interrupt
- * mode. We were previously in asynch/polling mode (using init_timer).
- *
- * We attempt to switch to interrupt mode here by calling
- * request_irq. If that works out, we enable receive interrupts.
- */
-static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
-{
- unsigned long flags;
-
- if (port) {
- DPRINTF("sn_console: switching to interrupt driven console\n");
-
- if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
- IRQF_SHARED,
- "SAL console driver", port) >= 0) {
- spin_lock_irqsave(&port->sc_port.lock, flags);
- port->sc_port.irq = SGI_UART_VECTOR;
- port->sc_ops = &intr_ops;
- irq_set_handler(port->sc_port.irq, handle_level_irq);
-
- /* turn on receive interrupts */
- ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV);
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
- }
- else {
- printk(KERN_INFO
- "sn_console: console proceeding in polled mode\n");
- }
- }
-}
-
-/*
- * Kernel console definitions
- */
-
-static void sn_sal_console_write(struct console *, const char *, unsigned);
-static int sn_sal_console_setup(struct console *, char *);
-static struct uart_driver sal_console_uart;
-extern struct tty_driver *uart_console_device(struct console *, int *);
-
-static struct console sal_console = {
- .name = DEVICE_NAME,
- .write = sn_sal_console_write,
- .device = uart_console_device,
- .setup = sn_sal_console_setup,
- .index = -1, /* unspecified */
- .data = &sal_console_uart,
-};
-
-#define SAL_CONSOLE &sal_console
-
-static struct uart_driver sal_console_uart = {
- .owner = THIS_MODULE,
- .driver_name = "sn_console",
- .dev_name = DEVICE_NAME,
- .major = 0, /* major/minor set at registration time per USE_DYNAMIC_MINOR */
- .minor = 0,
- .nr = 1, /* one port */
- .cons = SAL_CONSOLE,
-};
-
-/**
- * sn_sal_init - When the kernel loads us, get us rolling w/ serial core
- *
- * Before this is called, we've been printing kernel messages in a special
- * early mode not making use of the serial core infrastructure. When our
- * driver is loaded for real, we register the driver and port with serial
- * core and try to enable interrupt driven mode.
- *
- */
-static int __init sn_sal_init(void)
-{
- int retval;
-
- if (!ia64_platform_is("sn2"))
- return 0;
-
- printk(KERN_INFO "sn_console: Console driver init\n");
-
- if (USE_DYNAMIC_MINOR == 1) {
- misc.minor = MISC_DYNAMIC_MINOR;
- misc.name = DEVICE_NAME_DYNAMIC;
- retval = misc_register(&misc);
- if (retval != 0) {
- printk(KERN_WARNING "Failed to register console "
- "device using misc_register.\n");
- return -ENODEV;
- }
- sal_console_uart.major = MISC_MAJOR;
- sal_console_uart.minor = misc.minor;
- } else {
- sal_console_uart.major = DEVICE_MAJOR;
- sal_console_uart.minor = DEVICE_MINOR;
- }
-
- /* We register the driver and the port before switching to interrupts
- * or async above so the proper uart structures are populated */
-
- if (uart_register_driver(&sal_console_uart) < 0) {
- printk
- ("ERROR sn_sal_init failed uart_register_driver, line %d\n",
- __LINE__);
- return -ENODEV;
- }
-
- spin_lock_init(&sal_console_port.sc_port.lock);
-
- /* Setup the port struct with the minimum needed */
- sal_console_port.sc_port.membase = (char *)1; /* just needs to be non-zero */
- sal_console_port.sc_port.type = PORT_16550A;
- sal_console_port.sc_port.fifosize = SN_SAL_MAX_CHARS;
- sal_console_port.sc_port.ops = &sn_console_ops;
- sal_console_port.sc_port.line = 0;
-
- if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
- /* error - not sure what I'd do - so I'll do nothing */
- printk(KERN_ERR "%s: unable to add port\n", __func__);
- }
-
- /* when this driver is compiled in, the console initialization
- * will have already switched us into asynchronous operation
- * before we get here through the initcalls */
- if (!sal_console_port.sc_is_asynch) {
- sn_sal_switch_to_asynch(&sal_console_port);
- }
-
- /* at this point (device_init) we can try to turn on interrupts */
- if (!IS_RUNNING_ON_SIMULATOR()) {
- sn_sal_switch_to_interrupts(&sal_console_port);
- }
- sn_process_input = 1;
- return 0;
-}
-device_initcall(sn_sal_init);
-
-/**
- * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
- * @puts_raw : puts function to do the writing
- * @s: input string
- * @count: length
- *
- * We need a \r ahead of every \n for direct writes through
- * ia64_sn_console_putb (what sal_puts_raw below actually does).
- *
- */
-
-static void puts_raw_fixed(int (*puts_raw) (const char *s, int len),
- const char *s, int count)
-{
- const char *s1;
-
- /* Output '\r' before each '\n' */
- while ((s1 = memchr(s, '\n', count)) != NULL) {
- puts_raw(s, s1 - s);
- puts_raw("\r\n", 2);
- count -= s1 + 1 - s;
- s = s1 + 1;
- }
- puts_raw(s, count);
-}
-
-/**
- * sn_sal_console_write - Print statements before serial core available
- * @console: Console to operate on - we ignore since we have just one
- * @s: String to send
- * @count: length
- *
- * This is referenced in the console struct. It is used for early
- * console printing before we register with serial core and for things
- * such as kdb. The console_lock must be held when we get here.
- *
- * This function has some code for trying to print output even if the lock
- * is held. We try to cover the case where a lock holder could have died.
- * We don't use this special case code if we're not registered with serial
- * core yet. After we're registered with serial core, the only time this
- * function would be used is for high level kernel output like magic sys req,
- * kdb, and printk's.
- */
-static void
-sn_sal_console_write(struct console *co, const char *s, unsigned count)
-{
- unsigned long flags = 0;
- struct sn_cons_port *port = &sal_console_port;
- static int stole_lock = 0;
-
- BUG_ON(!port->sc_is_asynch);
-
- /* We can't look at the xmit buffer if we're not registered with serial core
- * yet. So only do the fancy recovery after registering
- */
- if (!port->sc_port.state) {
- /* Not yet registered with serial core - simple case */
- puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
- return;
- }
-
- /* somebody really wants this output, might be an
- * oops, kdb, panic, etc. make sure they get it. */
- if (!spin_trylock_irqsave(&port->sc_port.lock, flags)) {
- int lhead = port->sc_port.state->xmit.head;
- int ltail = port->sc_port.state->xmit.tail;
- int counter, got_lock = 0;
-
- /*
- * We attempt to determine if someone has died with the
- * lock. We wait ~20 secs after the head and tail ptrs
- * stop moving and assume the lock holder is not functional
- * and plow ahead. If the lock is freed within the time out
- * period we re-get the lock and go ahead normally. We also
- * remember if we have plowed ahead so that we don't have
- * to wait out the time out period again - the asumption
- * is that we will time out again.
- */
-
- for (counter = 0; counter < 150; mdelay(125), counter++) {
- if (stole_lock)
- break;
-
- if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
- got_lock = 1;
- break;
- } else {
- /* still locked */
- if ((lhead != port->sc_port.state->xmit.head)
- || (ltail !=
- port->sc_port.state->xmit.tail)) {
- lhead =
- port->sc_port.state->xmit.head;
- ltail =
- port->sc_port.state->xmit.tail;
- counter = 0;
- }
- }
- }
- /* flush anything in the serial core xmit buffer, raw */
- sn_transmit_chars(port, 1);
- if (got_lock) {
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
- stole_lock = 0;
- } else {
- /* fell thru */
- stole_lock = 1;
- }
- puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
- } else {
- stole_lock = 0;
- sn_transmit_chars(port, 1);
- spin_unlock_irqrestore(&port->sc_port.lock, flags);
-
- puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
- }
-}
-
-
-/**
- * sn_sal_console_setup - Set up console for early printing
- * @co: Console to work with
- * @options: Options to set
- *
- * Altix console doesn't do anything with baud rates, etc, anyway.
- *
- * This isn't required since not providing the setup function in the
- * console struct is ok. However, other patches like KDB plop something
- * here so providing it is easier.
- *
- */
-static int sn_sal_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
-/**
- * sn_sal_console_write_early - simple early output routine
- * @co - console struct
- * @s - string to print
- * @count - count
- *
- * Simple function to provide early output, before even
- * sn_sal_serial_console_init is called. Referenced in the
- * console struct registerd in sn_serial_console_early_setup.
- *
- */
-static void __init
-sn_sal_console_write_early(struct console *co, const char *s, unsigned count)
-{
- puts_raw_fixed(sal_console_port.sc_ops->sal_puts_raw, s, count);
-}
-
-/* Used for very early console printing - again, before
- * sn_sal_serial_console_init is run */
-static struct console sal_console_early __initdata = {
- .name = "sn_sal",
- .write = sn_sal_console_write_early,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-/**
- * sn_serial_console_early_setup - Sets up early console output support
- *
- * Register a console early on... This is for output before even
- * sn_sal_serial_cosnole_init is called. This function is called from
- * setup.c. This allows us to do really early polled writes. When
- * sn_sal_serial_console_init is called, this console is unregistered
- * and a new one registered.
- */
-int __init sn_serial_console_early_setup(void)
-{
- if (!ia64_platform_is("sn2"))
- return -1;
-
- sal_console_port.sc_ops = &poll_ops;
- spin_lock_init(&sal_console_port.sc_port.lock);
- early_sn_setup(); /* Find SAL entry points */
- register_console(&sal_console_early);
-
- return 0;
-}
-
-/**
- * sn_sal_serial_console_init - Early console output - set up for register
- *
- * This function is called when regular console init happens. Because we
- * support even earlier console output with sn_serial_console_early_setup
- * (called from setup.c directly), this function unregisters the really
- * early console.
- *
- * Note: Even if setup.c doesn't register sal_console_early, unregistering
- * it here doesn't hurt anything.
- *
- */
-static int __init sn_sal_serial_console_init(void)
-{
- if (ia64_platform_is("sn2")) {
- sn_sal_switch_to_asynch(&sal_console_port);
- DPRINTF("sn_sal_serial_console_init : register console\n");
- register_console(&sal_console);
- unregister_console(&sal_console_early);
- }
- return 0;
-}
-
-console_initcall(sn_sal_serial_console_init);