/*
* 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.
*/
/*
* 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;
stru