<commit_before>/*
 * 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-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/serialP.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/comsumer 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;
} ioc4_serial;

/* 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 int inline 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(&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;<commit_msg>TTY: serial, use atomic_inc_return in ioc4_serial<commit_after>/*
 * 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-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/serialP.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/comsumer 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;
} ioc4_serial;

/* 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 int inline 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;
{'fraction_non_alphanumeric': 0.09665029899363119, 'fraction_numerical': 0.060430745296319706, 'mean_word_length': 4.05720373709228, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 283, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 54, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5979526', 'n_tokens_mistral': 29905, 'n_tokens_neox': 26751, 'n_words': 5766}