diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3973d4b..47c705f 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -3,7 +3,7 @@ config MIPS default y select ARCH_SUPPORTS_UPROBES select ARCH_MIGHT_HAVE_PC_PARPORT - select ARCH_MIGHT_HAVE_PC_SERIO + select ARCH_MIGHT_HAVE_PC_SERIO if !SGI_IOC3 select ARCH_USE_CMPXCHG_LOCKREF if 64BIT select ARCH_USE_BUILTIN_BSWAP select HAVE_CONTEXT_TRACKING diff --git a/arch/mips/include/asm/sgi/ioc3.h b/arch/mips/include/asm/sgi/ioc3.h new file mode 100644 index 0000000..8890370 --- /dev/null +++ b/arch/mips/include/asm/sgi/ioc3.h @@ -0,0 +1,593 @@ +/* + * Copyright (C) 1999, 2000 Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + */ +#ifndef MIPS_SN_IOC3_H +#define MIPS_SN_IOC3_H + +#include + +/* serial port register map */ +struct ioc3_serialregs { + uint32_t sscr; + uint32_t stpir; + uint32_t stcir; + uint32_t srpir; + uint32_t srcir; + uint32_t srtr; + uint32_t shadow; +}; + +/* SUPERIO uart register map */ +struct ioc3_uartregs { + union { + char rbr; /* read only, DLAB == 0 */ + char thr; /* write only, DLAB == 0 */ + char dll; /* DLAB == 1 */ + } u1; + union { + char ier; /* DLAB == 0 */ + char dlm; /* DLAB == 1 */ + } u2; + union { + char iir; /* read only */ + char fcr; /* write only */ + } u3; + char iu_lcr; + char iu_mcr; + char iu_lsr; + char iu_msr; + char iu_scr; +}; + +#define iu_rbr u1.rbr +#define iu_thr u1.thr +#define iu_dll u1.dll +#define iu_ier u2.ier +#define iu_dlm u2.dlm +#define iu_iir u3.iir +#define iu_fcr u3.fcr + +struct ioc3_sioregs { + char fill[0x141]; /* starts at 0x141 */ + + char uartc; + char kbdcg; + + char fill0[0x150 - 0x142 - 1]; + + char pp_data; + char pp_dsr; + char pp_dcr; + + char fill1[0x158 - 0x152 - 1]; + + char pp_fifa; + char pp_cfgb; + char pp_ecr; + + char fill2[0x168 - 0x15a - 1]; + + char rtcad; + char rtcdat; + + char fill3[0x170 - 0x169 - 1]; + + struct ioc3_uartregs uartb; /* 0x20170 */ + struct ioc3_uartregs uarta; /* 0x20178 */ +}; + +/* Register layout of IOC3 in configuration space. */ +struct ioc3 { + /* PCI Config Space registers */ + uint32_t pci_id; /* 0x00000 */ + uint32_t pci_scr; /* 0x00004 */ + uint32_t pci_rev; /* 0x00008 */ + uint32_t pci_lat; /* 0x0000c */ + uint32_t pci_addr; /* 0x00010 */ + uint32_t pci_err_addr_l; /* 0x00014 */ + uint32_t pci_err_addr_h; /* 0x00018 */ + + uint32_t sio_ir; /* 0x0001c */ + uint32_t sio_ies; /* 0x00020 */ + uint32_t sio_iec; /* 0x00024 */ + uint32_t sio_cr; /* 0x00028 */ + uint32_t int_out; /* 0x0002c */ + uint32_t mcr; /* 0x00030 */ + + /* General Purpose I/O registers */ + uint32_t gpcr_s; /* 0x00034 */ + uint32_t gpcr_c; /* 0x00038 */ + uint32_t gpdr; /* 0x0003c */ + uint32_t gppr[16]; /* 0x00040 */ + + /* Parallel Port Registers */ + uint32_t ppbr_h_a; /* 0x00080 */ + uint32_t ppbr_l_a; /* 0x00084 */ + uint32_t ppcr_a; /* 0x00088 */ + uint32_t ppcr; /* 0x0008c */ + uint32_t ppbr_h_b; /* 0x00090 */ + uint32_t ppbr_l_b; /* 0x00094 */ + uint32_t ppcr_b; /* 0x00098 */ + + /* Keyboard and Mouse Registers */ + uint32_t km_csr; /* 0x0009c */ + uint32_t k_rd; /* 0x000a0 */ + uint32_t m_rd; /* 0x000a4 */ + uint32_t k_wd; /* 0x000a8 */ + uint32_t m_wd; /* 0x000ac */ + + /* Serial Port Registers */ + uint32_t sbbr_h; /* 0x000b0 */ + uint32_t sbbr_l; /* 0x000b4 */ + struct ioc3_serialregs port_a; + struct ioc3_serialregs port_b; + + /* Ethernet Registers */ + uint32_t emcr; /* 0x000f0 */ + uint32_t eisr; /* 0x000f4 */ + uint32_t eier; /* 0x000f8 */ + uint32_t ercsr; /* 0x000fc */ + uint32_t erbr_h; /* 0x00100 */ + uint32_t erbr_l; /* 0x00104 */ + uint32_t erbar; /* 0x00108 */ + uint32_t ercir; /* 0x0010c */ + uint32_t erpir; /* 0x00110 */ + uint32_t ertr; /* 0x00114 */ + uint32_t etcsr; /* 0x00118 */ + uint32_t ersr; /* 0x0011c */ + uint32_t etcdc; /* 0x00120 */ + uint32_t ebir; /* 0x00124 */ + uint32_t etbr_h; /* 0x00128 */ + uint32_t etbr_l; /* 0x0012c */ + uint32_t etcir; /* 0x00130 */ + uint32_t etpir; /* 0x00134 */ + uint32_t emar_h; /* 0x00138 */ + uint32_t emar_l; /* 0x0013c */ + uint32_t ehar_h; /* 0x00140 */ + uint32_t ehar_l; /* 0x00144 */ + uint32_t micr; /* 0x00148 */ + uint32_t midr_r; /* 0x0014c */ + uint32_t midr_w; /* 0x00150 */ + uint32_t pad1[(0x20000 - 0x00154) / 4]; + + + /* SuperIO Registers XXX */ + struct ioc3_sioregs sregs; /* 0x20000 */ + uint32_t pad2[(0x40000 - 0x20180) / 4]; + + /* SSRAM Diagnostic Access */ + uint32_t ssram[(0x80000 - 0x40000) / 4]; + + /* Bytebus device offsets + 0x80000 - Access to the generic devices selected with DEV0 + 0x9FFFF bytebus DEV_SEL_0 + 0xA0000 - Access to the generic devices selected with DEV1 + 0xBFFFF bytebus DEV_SEL_1 + 0xC0000 - Access to the generic devices selected with DEV2 + 0xDFFFF bytebus DEV_SEL_2 + 0xE0000 - Access to the generic devices selected with DEV3 + 0xFFFFF bytebus DEV_SEL_3 */ +}; + + +#define PCI_LAT 0xc /* Latency Timer */ +#define PCI_SCR_DROP_MODE_EN 0x00008000 /* drop pios on parity err */ +#define UARTA_BASE 0x178 +#define UARTB_BASE 0x170 + +/* + * Bytebus device space + */ +#define IOC3_BYTEBUS_DEV0 0x80000L +#define IOC3_BYTEBUS_DEV1 0xa0000L +#define IOC3_BYTEBUS_DEV2 0xc0000L +#define IOC3_BYTEBUS_DEV3 0xe0000L + +/* + * Ethernet RX Buffer + */ +struct ioc3_erxbuf { + u32 w0; /* first word (valid,bcnt,cksum) */ + u32 err; /* second word various errors */ + /* next comes n bytes of padding */ + /* then the received ethernet frame itself */ +}; + +#define ERXBUF_IPCKSUM_MASK 0x0000ffff +#define ERXBUF_BYTECNT_MASK 0x07ff0000 +#define ERXBUF_BYTECNT_SHIFT 16 +#define ERXBUF_V 0x80000000 + +#define ERXBUF_CRCERR 0x00000001 /* aka RSV15 */ +#define ERXBUF_FRAMERR 0x00000002 /* aka RSV14 */ +#define ERXBUF_CODERR 0x00000004 /* aka RSV13 */ +#define ERXBUF_INVPREAMB 0x00000008 /* aka RSV18 */ +#define ERXBUF_LOLEN 0x00007000 /* aka RSV2_0 */ +#define ERXBUF_HILEN 0x03ff0000 /* aka RSV12_3 */ +#define ERXBUF_MULTICAST 0x04000000 /* aka RSV16 */ +#define ERXBUF_BROADCAST 0x08000000 /* aka RSV17 */ +#define ERXBUF_LONGEVENT 0x10000000 /* aka RSV19 */ +#define ERXBUF_BADPKT 0x20000000 /* aka RSV20 */ +#define ERXBUF_GOODPKT 0x40000000 /* aka RSV21 */ +#define ERXBUF_CARRIER 0x80000000 /* aka RSV22 */ + +/* + * Ethernet TX Descriptor + */ +#define ETXD_DATALEN 104 +struct ioc3_etxd { + u32 cmd; /* command field */ + u32 bufcnt; /* buffer counts field */ + u64 p1; /* buffer pointer 1 */ + u64 p2; /* buffer pointer 2 */ + u8 data[ETXD_DATALEN]; /* opt. tx data */ +}; + +#define ETXD_BYTECNT_MASK 0x000007ff /* total byte count */ +#define ETXD_INTWHENDONE 0x00001000 /* intr when done */ +#define ETXD_D0V 0x00010000 /* data 0 valid */ +#define ETXD_B1V 0x00020000 /* buf 1 valid */ +#define ETXD_B2V 0x00040000 /* buf 2 valid */ +#define ETXD_DOCHECKSUM 0x00080000 /* insert ip cksum */ +#define ETXD_CHKOFF_MASK 0x07f00000 /* cksum byte offset */ +#define ETXD_CHKOFF_SHIFT 20 + +#define ETXD_D0CNT_MASK 0x0000007f +#define ETXD_B1CNT_MASK 0x0007ff00 +#define ETXD_B1CNT_SHIFT 8 +#define ETXD_B2CNT_MASK 0x7ff00000 +#define ETXD_B2CNT_SHIFT 20 + +/* ------------------------------------------------------------------------- */ + +/* Superio Registers (PIO Access) */ +#define IOC3_SIO_BASE 0x20000 +#define IOC3_SIO_UARTC (IOC3_SIO_BASE+0x141) /* UART Config */ +#define IOC3_SIO_KBDCG (IOC3_SIO_BASE+0x142) /* KBD Config */ +#define IOC3_SIO_PP_BASE (IOC3_SIO_BASE+PP_BASE) /* Parallel Port */ +#define IOC3_SIO_RTC_BASE (IOC3_SIO_BASE+0x168) /* Real Time Clock */ +#define IOC3_SIO_UB_BASE (IOC3_SIO_BASE+UARTB_BASE) /* UART B */ +#define IOC3_SIO_UA_BASE (IOC3_SIO_BASE+UARTA_BASE) /* UART A */ + +/* SSRAM Diagnostic Access */ +#define IOC3_SSRAM IOC3_RAM_OFF /* base of SSRAM diagnostic access */ +#define IOC3_SSRAM_LEN 0x40000 /* 256kb (addr space size, may not be fully populated) */ +#define IOC3_SSRAM_DM 0x0000ffff /* data mask */ +#define IOC3_SSRAM_PM 0x00010000 /* parity mask */ + +/* bitmasks for PCI_SCR */ +#define PCI_SCR_PAR_RESP_EN 0x00000040 /* enb PCI parity checking */ +#define PCI_SCR_SERR_EN 0x00000100 /* enable the SERR# driver */ +#define PCI_SCR_DROP_MODE_EN 0x00008000 /* drop pios on parity err */ +#define PCI_SCR_RX_SERR (0x1 << 16) +#define PCI_SCR_DROP_MODE (0x1 << 17) +#define PCI_SCR_SIG_PAR_ERR (0x1 << 24) +#define PCI_SCR_SIG_TAR_ABRT (0x1 << 27) +#define PCI_SCR_RX_TAR_ABRT (0x1 << 28) +#define PCI_SCR_SIG_MST_ABRT (0x1 << 29) +#define PCI_SCR_SIG_SERR (0x1 << 30) +#define PCI_SCR_PAR_ERR (0x1 << 31) + +/* bitmasks for IOC3_KM_CSR */ +#define KM_CSR_K_WRT_PEND 0x00000001 /* kbd port xmitting or resetting */ +#define KM_CSR_M_WRT_PEND 0x00000002 /* mouse port xmitting or resetting */ +#define KM_CSR_K_LCB 0x00000004 /* Line Cntrl Bit for last KBD write */ +#define KM_CSR_M_LCB 0x00000008 /* same for mouse */ +#define KM_CSR_K_DATA 0x00000010 /* state of kbd data line */ +#define KM_CSR_K_CLK 0x00000020 /* state of kbd clock line */ +#define KM_CSR_K_PULL_DATA 0x00000040 /* pull kbd data line low */ +#define KM_CSR_K_PULL_CLK 0x00000080 /* pull kbd clock line low */ +#define KM_CSR_M_DATA 0x00000100 /* state of ms data line */ +#define KM_CSR_M_CLK 0x00000200 /* state of ms clock line */ +#define KM_CSR_M_PULL_DATA 0x00000400 /* pull ms data line low */ +#define KM_CSR_M_PULL_CLK 0x00000800 /* pull ms clock line low */ +#define KM_CSR_EMM_MODE 0x00001000 /* emulation mode */ +#define KM_CSR_SIM_MODE 0x00002000 /* clock X8 */ +#define KM_CSR_K_SM_IDLE 0x00004000 /* Keyboard is idle */ +#define KM_CSR_M_SM_IDLE 0x00008000 /* Mouse is idle */ +#define KM_CSR_K_TO 0x00010000 /* Keyboard trying to send/receive */ +#define KM_CSR_M_TO 0x00020000 /* Mouse trying to send/receive */ +#define KM_CSR_K_TO_EN 0x00040000 /* KM_CSR_K_TO + KM_CSR_K_TO_EN = cause + SIO_IR to assert */ +#define KM_CSR_M_TO_EN 0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN = cause + SIO_IR to assert */ +#define KM_CSR_K_CLAMP_ONE 0x00100000 /* Pull K_CLK low after recv 1 char */ +#define KM_CSR_M_CLAMP_ONE 0x00200000 /* Pull M_CLK low after recv 1 char */ +#define KM_CSR_K_CLAMP_THREE 0x00400000 /* Pull K_CLK low after recv 3 chars */ +#define KM_CSR_M_CLAMP_THREE 0x00800000 /* Pull M_CLK low after recv 3 chars */ + +/* bitmasks for IOC3_K_RD and IOC3_M_RD */ +#define KM_RD_DATA_2 0x000000ff /* 3rd char recvd since last read */ +#define KM_RD_DATA_2_SHIFT 0 +#define KM_RD_DATA_1 0x0000ff00 /* 2nd char recvd since last read */ +#define KM_RD_DATA_1_SHIFT 8 +#define KM_RD_DATA_0 0x00ff0000 /* 1st char recvd since last read */ +#define KM_RD_DATA_0_SHIFT 16 +#define KM_RD_FRAME_ERR_2 0x01000000 /* framing or parity error in byte 2 */ +#define KM_RD_FRAME_ERR_1 0x02000000 /* same for byte 1 */ +#define KM_RD_FRAME_ERR_0 0x04000000 /* same for byte 0 */ + +#define KM_RD_KBD_MSE 0x08000000 /* 0 if from kbd, 1 if from mouse */ +#define KM_RD_OFLO 0x10000000 /* 4th char recvd before this read */ +#define KM_RD_VALID_2 0x20000000 /* DATA_2 valid */ +#define KM_RD_VALID_1 0x40000000 /* DATA_1 valid */ +#define KM_RD_VALID_0 0x80000000 /* DATA_0 valid */ +#define KM_RD_VALID_ALL (KM_RD_VALID_0|KM_RD_VALID_1|KM_RD_VALID_2) + +/* bitmasks for IOC3_K_WD & IOC3_M_WD */ +#define KM_WD_WRT_DATA 0x000000ff /* write to keyboard/mouse port */ +#define KM_WD_WRT_DATA_SHIFT 0 + +/* bitmasks for serial RX status byte */ +#define RXSB_OVERRUN 0x01 /* char(s) lost */ +#define RXSB_PAR_ERR 0x02 /* parity error */ +#define RXSB_FRAME_ERR 0x04 /* framing error */ +#define RXSB_BREAK 0x08 /* break character */ +#define RXSB_CTS 0x10 /* state of CTS */ +#define RXSB_DCD 0x20 /* state of DCD */ +#define RXSB_MODEM_VALID 0x40 /* DCD, CTS and OVERRUN are valid */ +#define RXSB_DATA_VALID 0x80 /* data byte, FRAME_ERR PAR_ERR & BREAK valid */ + +/* bitmasks for serial TX control byte */ +#define TXCB_INT_WHEN_DONE 0x20 /* interrupt after this byte is sent */ +#define TXCB_INVALID 0x00 /* byte is invalid */ +#define TXCB_VALID 0x40 /* byte is valid */ +#define TXCB_MCR 0x80 /* data<7:0> to modem control register */ +#define TXCB_DELAY 0xc0 /* delay data<7:0> mSec */ + +/* bitmasks for IOC3_SBBR_L */ +#define SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */ +#define SBBR_L_BASE 0xfffff000 /* lower serial ring base addr */ + +/* bitmasks for IOC3_SSCR_ */ +#define SSCR_RX_THRESHOLD 0x000001ff /* hiwater mark */ +#define SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ +#define SSCR_HFC_EN 0x00020000 /* hardware flow control enabled */ +#define SSCR_RX_RING_DCD 0x00040000 /* post RX record on delta-DCD */ +#define SSCR_RX_RING_CTS 0x00080000 /* post RX record on delta-CTS */ +#define SSCR_HIGH_SPD 0x00100000 /* 4X speed */ +#define SSCR_DIAG 0x00200000 /* bypass clock divider for sim */ +#define SSCR_RX_DRAIN 0x08000000 /* drain RX buffer to memory */ +#define SSCR_DMA_EN 0x10000000 /* enable ring buffer DMA */ +#define SSCR_DMA_PAUSE 0x20000000 /* pause DMA */ +#define SSCR_PAUSE_STATE 0x40000000 /* sets when PAUSE takes effect */ +#define SSCR_RESET 0x80000000 /* reset DMA channels */ + +/* all producer/comsumer pointers are the same bitfield */ +#define PROD_CONS_PTR_4K 0x00000ff8 /* for 4K buffers */ +#define PROD_CONS_PTR_1K 0x000003f8 /* for 1K buffers */ +#define PROD_CONS_PTR_OFF 3 + +/* bitmasks for IOC3_SRCIR_ */ +#define SRCIR_ARM 0x80000000 /* arm RX timer */ + +/* bitmasks for IOC3_SRPIR_ */ +#define SRPIR_BYTE_CNT 0x07000000 /* bytes in packer */ +#define SRPIR_BYTE_CNT_SHIFT 24 + +/* bitmasks for IOC3_STCIR_ */ +#define STCIR_BYTE_CNT 0x0f000000 /* bytes in unpacker */ +#define STCIR_BYTE_CNT_SHIFT 24 + +/* bitmasks for IOC3_SHADOW_ */ +#define SHADOW_DR 0x00000001 /* data ready */ +#define SHADOW_OE 0x00000002 /* overrun error */ +#define SHADOW_PE 0x00000004 /* parity error */ +#define SHADOW_FE 0x00000008 /* framing error */ +#define SHADOW_BI 0x00000010 /* break interrupt */ +#define SHADOW_THRE 0x00000020 /* transmit holding register empty */ +#define SHADOW_TEMT 0x00000040 /* transmit shift register empty */ +#define SHADOW_RFCE 0x00000080 /* char in RX fifo has an error */ +#define SHADOW_DCTS 0x00010000 /* delta clear to send */ +#define SHADOW_DDCD 0x00080000 /* delta data carrier detect */ +#define SHADOW_CTS 0x00100000 /* clear to send */ +#define SHADOW_DCD 0x00800000 /* data carrier detect */ +#define SHADOW_DTR 0x01000000 /* data terminal ready */ +#define SHADOW_RTS 0x02000000 /* request to send */ +#define SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ +#define SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ +#define SHADOW_LOOP 0x10000000 /* loopback enabled */ + +/* bitmasks for IOC3_SRTR_ */ +#define SRTR_CNT 0x00000fff /* reload value for RX timer */ +#define SRTR_CNT_VAL 0x0fff0000 /* current value of RX timer */ +#define SRTR_CNT_VAL_SHIFT 16 +#define SRTR_HZ 16000 /* SRTR clock frequency */ + +/* bitmasks for IOC3_SIO_IR, IOC3_SIO_IEC and IOC3_SIO_IES */ +#define SIO_IR_SA_TX_MT 0x00000001 /* Serial port A TX empty */ +#define SIO_IR_SA_RX_FULL 0x00000002 /* port A RX buf full */ +#define SIO_IR_SA_RX_HIGH 0x00000004 /* port A RX hiwat */ +#define SIO_IR_SA_RX_TIMER 0x00000008 /* port A RX timeout */ +#define SIO_IR_SA_DELTA_DCD 0x00000010 /* port A delta DCD */ +#define SIO_IR_SA_DELTA_CTS 0x00000020 /* port A delta CTS */ +#define SIO_IR_SA_INT 0x00000040 /* port A pass-thru intr */ +#define SIO_IR_SA_TX_EXPLICIT 0x00000080 /* port A explicit TX thru */ +#define SIO_IR_SA_MEMERR 0x00000100 /* port A PCI error */ +#define SIO_IR_SB_TX_MT 0x00000200 /* */ +#define SIO_IR_SB_RX_FULL 0x00000400 /* */ +#define SIO_IR_SB_RX_HIGH 0x00000800 /* */ +#define SIO_IR_SB_RX_TIMER 0x00001000 /* */ +#define SIO_IR_SB_DELTA_DCD 0x00002000 /* */ +#define SIO_IR_SB_DELTA_CTS 0x00004000 /* */ +#define SIO_IR_SB_INT 0x00008000 /* */ +#define SIO_IR_SB_TX_EXPLICIT 0x00010000 /* */ +#define SIO_IR_SB_MEMERR 0x00020000 /* */ +#define SIO_IR_PP_INT 0x00040000 /* P port pass-thru intr */ +#define SIO_IR_PP_INTA 0x00080000 /* PP context A thru */ +#define SIO_IR_PP_INTB 0x00100000 /* PP context B thru */ +#define SIO_IR_PP_MEMERR 0x00200000 /* PP PCI error */ +#define SIO_IR_KBD_INT 0x00400000 /* kbd/mouse intr */ +#define SIO_IR_RT_INT 0x08000000 /* RT output pulse */ +#define SIO_IR_GEN_INT1 0x10000000 /* RT input pulse */ +#define SIO_IR_GEN_INT_SHIFT 28 + +/* per device interrupt masks */ +#define SIO_IR_SA (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) +#define SIO_IR_SB (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) +#define SIO_IR_PP (SIO_IR_PP_INT | SIO_IR_PP_INTA | \ + SIO_IR_PP_INTB | SIO_IR_PP_MEMERR) +#define SIO_IR_RT (SIO_IR_RT_INT | SIO_IR_GEN_INT1) + +/* bitmasks for SIO_CR */ +#define SIO_CR_SIO_RESET 0x00000001 /* reset the SIO */ +#define SIO_CR_SER_A_BASE 0x000000fe /* DMA poll addr port A */ +#define SIO_CR_SER_A_BASE_SHIFT 1 +#define SIO_CR_SER_B_BASE 0x00007f00 /* DMA poll addr port B */ +#define SIO_CR_SER_B_BASE_SHIFT 8 +#define SIO_SR_CMD_PULSE 0x00078000 /* byte bus strobe length */ +#define SIO_CR_CMD_PULSE_SHIFT 15 +#define SIO_CR_ARB_DIAG 0x00380000 /* cur !enet PCI requet (ro) */ +#define SIO_CR_ARB_DIAG_TXA 0x00000000 +#define SIO_CR_ARB_DIAG_RXA 0x00080000 +#define SIO_CR_ARB_DIAG_TXB 0x00100000 +#define SIO_CR_ARB_DIAG_RXB 0x00180000 +#define SIO_CR_ARB_DIAG_PP 0x00200000 +#define SIO_CR_ARB_DIAG_IDLE 0x00400000 /* 0 -> active request (ro) */ + +/* bitmasks for INT_OUT */ +#define INT_OUT_COUNT 0x0000ffff /* pulse interval timer */ +#define INT_OUT_MODE 0x00070000 /* mode mask */ +#define INT_OUT_MODE_0 0x00000000 /* set output to 0 */ +#define INT_OUT_MODE_1 0x00040000 /* set output to 1 */ +#define INT_OUT_MODE_1PULSE 0x00050000 /* send 1 pulse */ +#define INT_OUT_MODE_PULSES 0x00060000 /* send 1 pulse every interval */ +#define INT_OUT_MODE_SQW 0x00070000 /* toggle output every interval */ +#define INT_OUT_DIAG 0x40000000 /* diag mode */ +#define INT_OUT_INT_OUT 0x80000000 /* current state of INT_OUT */ + +/* time constants for INT_OUT */ +#define INT_OUT_NS_PER_TICK (30 * 260) /* 30 ns PCI clock, divisor=260 */ +#define INT_OUT_TICKS_PER_PULSE 3 /* outgoing pulse lasts 3 ticks */ +#define INT_OUT_US_TO_COUNT(x) /* convert uS to a count value */ \ + (((x) * 10 + INT_OUT_NS_PER_TICK / 200) * \ + 100 / INT_OUT_NS_PER_TICK - 1) +#define INT_OUT_COUNT_TO_US(x) /* convert count value to uS */ \ + (((x) + 1) * INT_OUT_NS_PER_TICK / 1000) +#define INT_OUT_MIN_TICKS 3 /* min period is width of pulse in "ticks" */ +#define INT_OUT_MAX_TICKS INT_OUT_COUNT /* largest possible count */ + +/* bitmasks for GPCR */ +#define GPCR_DIR 0x000000ff /* tristate pin input or output */ +#define GPCR_DIR_PIN(x) (1<<(x)) /* access one of the DIR bits */ +#define GPCR_EDGE 0x000f0000 /* extint edge or level sensitive */ +#define GPCR_EDGE_PIN(x) (1<<((x)+15)) /* access one of the EDGE bits */ + +/* values for GPCR */ +#define GPCR_INT_OUT_EN 0x00100000 /* enable INT_OUT to pin 0 */ +#define GPCR_MLAN_EN 0x00200000 /* enable MCR to pin 8 */ +#define GPCR_DIR_SERA_XCVR 0x00000080 /* Port A Transceiver select enable */ +#define GPCR_DIR_SERB_XCVR 0x00000040 /* Port B Transceiver select enable */ +#define GPCR_DIR_PHY_RST 0x00000020 /* ethernet PHY reset enable */ + +/* defs for some of the generic I/O pins */ +#define GPCR_PHY_RESET 0x20 /* pin is output to PHY reset */ +#define GPCR_UARTB_MODESEL 0x40 /* pin is output to port B mode sel */ +#define GPCR_UARTA_MODESEL 0x80 /* pin is output to port A mode sel */ + +#define GPPR_PHY_RESET_PIN 5 /* GIO pin cntrlling phy reset */ +#define GPPR_UARTB_MODESEL_PIN 6 /* GIO pin cntrlling uart b mode sel */ +#define GPPR_UARTA_MODESEL_PIN 7 /* GIO pin cntrlling uart a mode sel */ + +/* ethernet */ +#define EMCR_DUPLEX 0x00000001 +#define EMCR_PROMISC 0x00000002 +#define EMCR_PADEN 0x00000004 +#define EMCR_RXOFF_MASK 0x000001f8 +#define EMCR_RXOFF_SHIFT 3 +#define EMCR_RAMPAR 0x00000200 +#define EMCR_BADPAR 0x00000800 +#define EMCR_BUFSIZ 0x00001000 +#define EMCR_TXDMAEN 0x00002000 +#define EMCR_TXEN 0x00004000 +#define EMCR_RXDMAEN 0x00008000 +#define EMCR_RXEN 0x00010000 +#define EMCR_LOOPBACK 0x00020000 +#define EMCR_ARB_DIAG 0x001c0000 +#define EMCR_ARB_DIAG_IDLE 0x00200000 +#define EMCR_RST 0x80000000 + +#define EISR_RXTIMERINT 0x00000001 +#define EISR_RXTHRESHINT 0x00000002 +#define EISR_RXOFLO 0x00000004 +#define EISR_RXBUFOFLO 0x00000008 +#define EISR_RXMEMERR 0x00000010 +#define EISR_RXPARERR 0x00000020 +#define EISR_TXEMPTY 0x00010000 +#define EISR_TXRTRY 0x00020000 +#define EISR_TXEXDEF 0x00040000 +#define EISR_TXLCOL 0x00080000 +#define EISR_TXGIANT 0x00100000 +#define EISR_TXBUFUFLO 0x00200000 +#define EISR_TXEXPLICIT 0x00400000 +#define EISR_TXCOLLWRAP 0x00800000 +#define EISR_TXDEFERWRAP 0x01000000 +#define EISR_TXMEMERR 0x02000000 +#define EISR_TXPARERR 0x04000000 + +#define ERCSR_THRESH_MASK 0x000001ff /* enet RX threshold */ +#define ERCSR_RX_TMR 0x40000000 /* simulation only */ +#define ERCSR_DIAG_OFLO 0x80000000 /* simulation only */ + +#define ERBR_ALIGNMENT 4096 +#define ERBR_L_RXRINGBASE_MASK 0xfffff000 + +#define ERBAR_BARRIER_BIT 0x0100 +#define ERBAR_RXBARR_MASK 0xffff0000 +#define ERBAR_RXBARR_SHIFT 16 + +#define ERCIR_RXCONSUME_MASK 0x00000fff + +#define ERPIR_RXPRODUCE_MASK 0x00000fff +#define ERPIR_ARM 0x80000000 + +#define ERTR_CNT_MASK 0x000007ff + +#define ETCSR_IPGT_MASK 0x0000007f +#define ETCSR_IPGR1_MASK 0x00007f00 +#define ETCSR_IPGR1_SHIFT 8 +#define ETCSR_IPGR2_MASK 0x007f0000 +#define ETCSR_IPGR2_SHIFT 16 +#define ETCSR_NOTXCLK 0x80000000 + +#define ETCDC_COLLCNT_MASK 0x0000ffff +#define ETCDC_DEFERCNT_MASK 0xffff0000 +#define ETCDC_DEFERCNT_SHIFT 16 + +#define ETBR_ALIGNMENT (64*1024) +#define ETBR_L_RINGSZ_MASK 0x00000001 +#define ETBR_L_RINGSZ128 0 +#define ETBR_L_RINGSZ512 1 +#define ETBR_L_TXRINGBASE_MASK 0xffffc000 + +#define ETCIR_TXCONSUME_MASK 0x0000ffff +#define ETCIR_IDLE 0x80000000 + +#define ETPIR_TXPRODUCE_MASK 0x0000ffff + +#define EBIR_TXBUFPROD_MASK 0x0000001f +#define EBIR_TXBUFCONS_MASK 0x00001f00 +#define EBIR_TXBUFCONS_SHIFT 8 +#define EBIR_RXBUFPROD_MASK 0x007fc000 +#define EBIR_RXBUFPROD_SHIFT 14 +#define EBIR_RXBUFCONS_MASK 0xff800000 +#define EBIR_RXBUFCONS_SHIFT 23 + +#define MICR_REGADDR_MASK 0x0000001f +#define MICR_PHYADDR_MASK 0x000003e0 +#define MICR_PHYADDR_SHIFT 5 +#define MICR_READTRIG 0x00000400 +#define MICR_BUSY 0x00000800 + +#define MIDR_DATA_MASK 0x0000ffff + +#endif /* MIPS_SN_IOC3_H */ diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h deleted file mode 100644 index e33f036..0000000 --- a/arch/mips/include/asm/sn/ioc3.h +++ /dev/null @@ -1,663 +0,0 @@ -/* - * Copyright (C) 1999, 2000 Ralf Baechle - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - */ -#ifndef _IOC3_H -#define _IOC3_H - -#include - -/* SUPERIO uart register map */ -typedef volatile struct ioc3_uartregs { - union { - volatile u8 rbr; /* read only, DLAB == 0 */ - volatile u8 thr; /* write only, DLAB == 0 */ - volatile u8 dll; /* DLAB == 1 */ - } u1; - union { - volatile u8 ier; /* DLAB == 0 */ - volatile u8 dlm; /* DLAB == 1 */ - } u2; - union { - volatile u8 iir; /* read only */ - volatile u8 fcr; /* write only */ - } u3; - volatile u8 iu_lcr; - volatile u8 iu_mcr; - volatile u8 iu_lsr; - volatile u8 iu_msr; - volatile u8 iu_scr; -} ioc3_uregs_t; - -#define iu_rbr u1.rbr -#define iu_thr u1.thr -#define iu_dll u1.dll -#define iu_ier u2.ier -#define iu_dlm u2.dlm -#define iu_iir u3.iir -#define iu_fcr u3.fcr - -struct ioc3_sioregs { - volatile u8 fill[0x141]; /* starts at 0x141 */ - - volatile u8 uartc; - volatile u8 kbdcg; - - volatile u8 fill0[0x150 - 0x142 - 1]; - - volatile u8 pp_data; - volatile u8 pp_dsr; - volatile u8 pp_dcr; - - volatile u8 fill1[0x158 - 0x152 - 1]; - - volatile u8 pp_fifa; - volatile u8 pp_cfgb; - volatile u8 pp_ecr; - - volatile u8 fill2[0x168 - 0x15a - 1]; - - volatile u8 rtcad; - volatile u8 rtcdat; - - volatile u8 fill3[0x170 - 0x169 - 1]; - - struct ioc3_uartregs uartb; /* 0x20170 */ - struct ioc3_uartregs uarta; /* 0x20178 */ -}; - -/* Register layout of IOC3 in configuration space. */ -struct ioc3 { - volatile u32 pad0[7]; /* 0x00000 */ - volatile u32 sio_ir; /* 0x0001c */ - volatile u32 sio_ies; /* 0x00020 */ - volatile u32 sio_iec; /* 0x00024 */ - volatile u32 sio_cr; /* 0x00028 */ - volatile u32 int_out; /* 0x0002c */ - volatile u32 mcr; /* 0x00030 */ - - /* General Purpose I/O registers */ - volatile u32 gpcr_s; /* 0x00034 */ - volatile u32 gpcr_c; /* 0x00038 */ - volatile u32 gpdr; /* 0x0003c */ - volatile u32 gppr_0; /* 0x00040 */ - volatile u32 gppr_1; /* 0x00044 */ - volatile u32 gppr_2; /* 0x00048 */ - volatile u32 gppr_3; /* 0x0004c */ - volatile u32 gppr_4; /* 0x00050 */ - volatile u32 gppr_5; /* 0x00054 */ - volatile u32 gppr_6; /* 0x00058 */ - volatile u32 gppr_7; /* 0x0005c */ - volatile u32 gppr_8; /* 0x00060 */ - volatile u32 gppr_9; /* 0x00064 */ - volatile u32 gppr_10; /* 0x00068 */ - volatile u32 gppr_11; /* 0x0006c */ - volatile u32 gppr_12; /* 0x00070 */ - volatile u32 gppr_13; /* 0x00074 */ - volatile u32 gppr_14; /* 0x00078 */ - volatile u32 gppr_15; /* 0x0007c */ - - /* Parallel Port Registers */ - volatile u32 ppbr_h_a; /* 0x00080 */ - volatile u32 ppbr_l_a; /* 0x00084 */ - volatile u32 ppcr_a; /* 0x00088 */ - volatile u32 ppcr; /* 0x0008c */ - volatile u32 ppbr_h_b; /* 0x00090 */ - volatile u32 ppbr_l_b; /* 0x00094 */ - volatile u32 ppcr_b; /* 0x00098 */ - - /* Keyboard and Mouse Registers */ - volatile u32 km_csr; /* 0x0009c */ - volatile u32 k_rd; /* 0x000a0 */ - volatile u32 m_rd; /* 0x000a4 */ - volatile u32 k_wd; /* 0x000a8 */ - volatile u32 m_wd; /* 0x000ac */ - - /* Serial Port Registers */ - volatile u32 sbbr_h; /* 0x000b0 */ - volatile u32 sbbr_l; /* 0x000b4 */ - volatile u32 sscr_a; /* 0x000b8 */ - volatile u32 stpir_a; /* 0x000bc */ - volatile u32 stcir_a; /* 0x000c0 */ - volatile u32 srpir_a; /* 0x000c4 */ - volatile u32 srcir_a; /* 0x000c8 */ - volatile u32 srtr_a; /* 0x000cc */ - volatile u32 shadow_a; /* 0x000d0 */ - volatile u32 sscr_b; /* 0x000d4 */ - volatile u32 stpir_b; /* 0x000d8 */ - volatile u32 stcir_b; /* 0x000dc */ - volatile u32 srpir_b; /* 0x000e0 */ - volatile u32 srcir_b; /* 0x000e4 */ - volatile u32 srtr_b; /* 0x000e8 */ - volatile u32 shadow_b; /* 0x000ec */ - - /* Ethernet Registers */ - volatile u32 emcr; /* 0x000f0 */ - volatile u32 eisr; /* 0x000f4 */ - volatile u32 eier; /* 0x000f8 */ - volatile u32 ercsr; /* 0x000fc */ - volatile u32 erbr_h; /* 0x00100 */ - volatile u32 erbr_l; /* 0x00104 */ - volatile u32 erbar; /* 0x00108 */ - volatile u32 ercir; /* 0x0010c */ - volatile u32 erpir; /* 0x00110 */ - volatile u32 ertr; /* 0x00114 */ - volatile u32 etcsr; /* 0x00118 */ - volatile u32 ersr; /* 0x0011c */ - volatile u32 etcdc; /* 0x00120 */ - volatile u32 ebir; /* 0x00124 */ - volatile u32 etbr_h; /* 0x00128 */ - volatile u32 etbr_l; /* 0x0012c */ - volatile u32 etcir; /* 0x00130 */ - volatile u32 etpir; /* 0x00134 */ - volatile u32 emar_h; /* 0x00138 */ - volatile u32 emar_l; /* 0x0013c */ - volatile u32 ehar_h; /* 0x00140 */ - volatile u32 ehar_l; /* 0x00144 */ - volatile u32 micr; /* 0x00148 */ - volatile u32 midr_r; /* 0x0014c */ - volatile u32 midr_w; /* 0x00150 */ - volatile u32 pad1[(0x20000 - 0x00154) / 4]; - - /* SuperIO Registers XXX */ - struct ioc3_sioregs sregs; /* 0x20000 */ - volatile u32 pad2[(0x40000 - 0x20180) / 4]; - - /* SSRAM Diagnostic Access */ - volatile u32 ssram[(0x80000 - 0x40000) / 4]; - - /* Bytebus device offsets - 0x80000 - Access to the generic devices selected with DEV0 - 0x9FFFF bytebus DEV_SEL_0 - 0xA0000 - Access to the generic devices selected with DEV1 - 0xBFFFF bytebus DEV_SEL_1 - 0xC0000 - Access to the generic devices selected with DEV2 - 0xDFFFF bytebus DEV_SEL_2 - 0xE0000 - Access to the generic devices selected with DEV3 - 0xFFFFF bytebus DEV_SEL_3 */ -}; - -/* - * Ethernet RX Buffer - */ -struct ioc3_erxbuf { - u32 w0; /* first word (valid,bcnt,cksum) */ - u32 err; /* second word various errors */ - /* next comes n bytes of padding */ - /* then the received ethernet frame itself */ -}; - -#define ERXBUF_IPCKSUM_MASK 0x0000ffff -#define ERXBUF_BYTECNT_MASK 0x07ff0000 -#define ERXBUF_BYTECNT_SHIFT 16 -#define ERXBUF_V 0x80000000 - -#define ERXBUF_CRCERR 0x00000001 /* aka RSV15 */ -#define ERXBUF_FRAMERR 0x00000002 /* aka RSV14 */ -#define ERXBUF_CODERR 0x00000004 /* aka RSV13 */ -#define ERXBUF_INVPREAMB 0x00000008 /* aka RSV18 */ -#define ERXBUF_LOLEN 0x00007000 /* aka RSV2_0 */ -#define ERXBUF_HILEN 0x03ff0000 /* aka RSV12_3 */ -#define ERXBUF_MULTICAST 0x04000000 /* aka RSV16 */ -#define ERXBUF_BROADCAST 0x08000000 /* aka RSV17 */ -#define ERXBUF_LONGEVENT 0x10000000 /* aka RSV19 */ -#define ERXBUF_BADPKT 0x20000000 /* aka RSV20 */ -#define ERXBUF_GOODPKT 0x40000000 /* aka RSV21 */ -#define ERXBUF_CARRIER 0x80000000 /* aka RSV22 */ - -/* - * Ethernet TX Descriptor - */ -#define ETXD_DATALEN 104 -struct ioc3_etxd { - u32 cmd; /* command field */ - u32 bufcnt; /* buffer counts field */ - u64 p1; /* buffer pointer 1 */ - u64 p2; /* buffer pointer 2 */ - u8 data[ETXD_DATALEN]; /* opt. tx data */ -}; - -#define ETXD_BYTECNT_MASK 0x000007ff /* total byte count */ -#define ETXD_INTWHENDONE 0x00001000 /* intr when done */ -#define ETXD_D0V 0x00010000 /* data 0 valid */ -#define ETXD_B1V 0x00020000 /* buf 1 valid */ -#define ETXD_B2V 0x00040000 /* buf 2 valid */ -#define ETXD_DOCHECKSUM 0x00080000 /* insert ip cksum */ -#define ETXD_CHKOFF_MASK 0x07f00000 /* cksum byte offset */ -#define ETXD_CHKOFF_SHIFT 20 - -#define ETXD_D0CNT_MASK 0x0000007f -#define ETXD_B1CNT_MASK 0x0007ff00 -#define ETXD_B1CNT_SHIFT 8 -#define ETXD_B2CNT_MASK 0x7ff00000 -#define ETXD_B2CNT_SHIFT 20 - -/* - * Bytebus device space - */ -#define IOC3_BYTEBUS_DEV0 0x80000L -#define IOC3_BYTEBUS_DEV1 0xa0000L -#define IOC3_BYTEBUS_DEV2 0xc0000L -#define IOC3_BYTEBUS_DEV3 0xe0000L - -/* ------------------------------------------------------------------------- */ - -/* Superio Registers (PIO Access) */ -#define IOC3_SIO_BASE 0x20000 -#define IOC3_SIO_UARTC (IOC3_SIO_BASE+0x141) /* UART Config */ -#define IOC3_SIO_KBDCG (IOC3_SIO_BASE+0x142) /* KBD Config */ -#define IOC3_SIO_PP_BASE (IOC3_SIO_BASE+PP_BASE) /* Parallel Port */ -#define IOC3_SIO_RTC_BASE (IOC3_SIO_BASE+0x168) /* Real Time Clock */ -#define IOC3_SIO_UB_BASE (IOC3_SIO_BASE+UARTB_BASE) /* UART B */ -#define IOC3_SIO_UA_BASE (IOC3_SIO_BASE+UARTA_BASE) /* UART A */ - -/* SSRAM Diagnostic Access */ -#define IOC3_SSRAM IOC3_RAM_OFF /* base of SSRAM diagnostic access */ -#define IOC3_SSRAM_LEN 0x40000 /* 256kb (address space size, may not be fully populated) */ -#define IOC3_SSRAM_DM 0x0000ffff /* data mask */ -#define IOC3_SSRAM_PM 0x00010000 /* parity mask */ - -/* bitmasks for PCI_SCR */ -#define PCI_SCR_PAR_RESP_EN 0x00000040 /* enb PCI parity checking */ -#define PCI_SCR_SERR_EN 0x00000100 /* enable the SERR# driver */ -#define PCI_SCR_DROP_MODE_EN 0x00008000 /* drop pios on parity err */ -#define PCI_SCR_RX_SERR (0x1 << 16) -#define PCI_SCR_DROP_MODE (0x1 << 17) -#define PCI_SCR_SIG_PAR_ERR (0x1 << 24) -#define PCI_SCR_SIG_TAR_ABRT (0x1 << 27) -#define PCI_SCR_RX_TAR_ABRT (0x1 << 28) -#define PCI_SCR_SIG_MST_ABRT (0x1 << 29) -#define PCI_SCR_SIG_SERR (0x1 << 30) -#define PCI_SCR_PAR_ERR (0x1 << 31) - -/* bitmasks for IOC3_KM_CSR */ -#define KM_CSR_K_WRT_PEND 0x00000001 /* kbd port xmitting or resetting */ -#define KM_CSR_M_WRT_PEND 0x00000002 /* mouse port xmitting or resetting */ -#define KM_CSR_K_LCB 0x00000004 /* Line Cntrl Bit for last KBD write */ -#define KM_CSR_M_LCB 0x00000008 /* same for mouse */ -#define KM_CSR_K_DATA 0x00000010 /* state of kbd data line */ -#define KM_CSR_K_CLK 0x00000020 /* state of kbd clock line */ -#define KM_CSR_K_PULL_DATA 0x00000040 /* pull kbd data line low */ -#define KM_CSR_K_PULL_CLK 0x00000080 /* pull kbd clock line low */ -#define KM_CSR_M_DATA 0x00000100 /* state of ms data line */ -#define KM_CSR_M_CLK 0x00000200 /* state of ms clock line */ -#define KM_CSR_M_PULL_DATA 0x00000400 /* pull ms data line low */ -#define KM_CSR_M_PULL_CLK 0x00000800 /* pull ms clock line low */ -#define KM_CSR_EMM_MODE 0x00001000 /* emulation mode */ -#define KM_CSR_SIM_MODE 0x00002000 /* clock X8 */ -#define KM_CSR_K_SM_IDLE 0x00004000 /* Keyboard is idle */ -#define KM_CSR_M_SM_IDLE 0x00008000 /* Mouse is idle */ -#define KM_CSR_K_TO 0x00010000 /* Keyboard trying to send/receive */ -#define KM_CSR_M_TO 0x00020000 /* Mouse trying to send/receive */ -#define KM_CSR_K_TO_EN 0x00040000 /* KM_CSR_K_TO + KM_CSR_K_TO_EN = cause - SIO_IR to assert */ -#define KM_CSR_M_TO_EN 0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN = cause - SIO_IR to assert */ -#define KM_CSR_K_CLAMP_ONE 0x00100000 /* Pull K_CLK low after rec. one char */ -#define KM_CSR_M_CLAMP_ONE 0x00200000 /* Pull M_CLK low after rec. one char */ -#define KM_CSR_K_CLAMP_THREE 0x00400000 /* Pull K_CLK low after rec. three chars */ -#define KM_CSR_M_CLAMP_THREE 0x00800000 /* Pull M_CLK low after rec. three char */ - -/* bitmasks for IOC3_K_RD and IOC3_M_RD */ -#define KM_RD_DATA_2 0x000000ff /* 3rd char recvd since last read */ -#define KM_RD_DATA_2_SHIFT 0 -#define KM_RD_DATA_1 0x0000ff00 /* 2nd char recvd since last read */ -#define KM_RD_DATA_1_SHIFT 8 -#define KM_RD_DATA_0 0x00ff0000 /* 1st char recvd since last read */ -#define KM_RD_DATA_0_SHIFT 16 -#define KM_RD_FRAME_ERR_2 0x01000000 /* framing or parity error in byte 2 */ -#define KM_RD_FRAME_ERR_1 0x02000000 /* same for byte 1 */ -#define KM_RD_FRAME_ERR_0 0x04000000 /* same for byte 0 */ - -#define KM_RD_KBD_MSE 0x08000000 /* 0 if from kbd, 1 if from mouse */ -#define KM_RD_OFLO 0x10000000 /* 4th char recvd before this read */ -#define KM_RD_VALID_2 0x20000000 /* DATA_2 valid */ -#define KM_RD_VALID_1 0x40000000 /* DATA_1 valid */ -#define KM_RD_VALID_0 0x80000000 /* DATA_0 valid */ -#define KM_RD_VALID_ALL (KM_RD_VALID_0|KM_RD_VALID_1|KM_RD_VALID_2) - -/* bitmasks for IOC3_K_WD & IOC3_M_WD */ -#define KM_WD_WRT_DATA 0x000000ff /* write to keyboard/mouse port */ -#define KM_WD_WRT_DATA_SHIFT 0 - -/* bitmasks for serial RX status byte */ -#define RXSB_OVERRUN 0x01 /* char(s) lost */ -#define RXSB_PAR_ERR 0x02 /* parity error */ -#define RXSB_FRAME_ERR 0x04 /* framing error */ -#define RXSB_BREAK 0x08 /* break character */ -#define RXSB_CTS 0x10 /* state of CTS */ -#define RXSB_DCD 0x20 /* state of DCD */ -#define RXSB_MODEM_VALID 0x40 /* DCD, CTS and OVERRUN are valid */ -#define RXSB_DATA_VALID 0x80 /* data byte, FRAME_ERR PAR_ERR & BREAK valid */ - -/* bitmasks for serial TX control byte */ -#define TXCB_INT_WHEN_DONE 0x20 /* interrupt after this byte is sent */ -#define TXCB_INVALID 0x00 /* byte is invalid */ -#define TXCB_VALID 0x40 /* byte is valid */ -#define TXCB_MCR 0x80 /* data<7:0> to modem control register */ -#define TXCB_DELAY 0xc0 /* delay data<7:0> mSec */ - -/* bitmasks for IOC3_SBBR_L */ -#define SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */ -#define SBBR_L_BASE 0xfffff000 /* lower serial ring base addr */ - -/* bitmasks for IOC3_SSCR_ */ -#define SSCR_RX_THRESHOLD 0x000001ff /* hiwater mark */ -#define SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */ -#define SSCR_HFC_EN 0x00020000 /* hardware flow control enabled */ -#define SSCR_RX_RING_DCD 0x00040000 /* post RX record on delta-DCD */ -#define SSCR_RX_RING_CTS 0x00080000 /* post RX record on delta-CTS */ -#define SSCR_HIGH_SPD 0x00100000 /* 4X speed */ -#define SSCR_DIAG 0x00200000 /* bypass clock divider for sim */ -#define SSCR_RX_DRAIN 0x08000000 /* drain RX buffer to memory */ -#define SSCR_DMA_EN 0x10000000 /* enable ring buffer DMA */ -#define SSCR_DMA_PAUSE 0x20000000 /* pause DMA */ -#define SSCR_PAUSE_STATE 0x40000000 /* sets when PAUSE takes effect */ -#define SSCR_RESET 0x80000000 /* reset DMA channels */ - -/* all producer/comsumer pointers are the same bitfield */ -#define PROD_CONS_PTR_4K 0x00000ff8 /* for 4K buffers */ -#define PROD_CONS_PTR_1K 0x000003f8 /* for 1K buffers */ -#define PROD_CONS_PTR_OFF 3 - -/* bitmasks for IOC3_SRCIR_ */ -#define SRCIR_ARM 0x80000000 /* arm RX timer */ - -/* bitmasks for IOC3_SRPIR_ */ -#define SRPIR_BYTE_CNT 0x07000000 /* bytes in packer */ -#define SRPIR_BYTE_CNT_SHIFT 24 - -/* bitmasks for IOC3_STCIR_ */ -#define STCIR_BYTE_CNT 0x0f000000 /* bytes in unpacker */ -#define STCIR_BYTE_CNT_SHIFT 24 - -/* bitmasks for IOC3_SHADOW_ */ -#define SHADOW_DR 0x00000001 /* data ready */ -#define SHADOW_OE 0x00000002 /* overrun error */ -#define SHADOW_PE 0x00000004 /* parity error */ -#define SHADOW_FE 0x00000008 /* framing error */ -#define SHADOW_BI 0x00000010 /* break interrupt */ -#define SHADOW_THRE 0x00000020 /* transmit holding register empty */ -#define SHADOW_TEMT 0x00000040 /* transmit shift register empty */ -#define SHADOW_RFCE 0x00000080 /* char in RX fifo has an error */ -#define SHADOW_DCTS 0x00010000 /* delta clear to send */ -#define SHADOW_DDCD 0x00080000 /* delta data carrier detect */ -#define SHADOW_CTS 0x00100000 /* clear to send */ -#define SHADOW_DCD 0x00800000 /* data carrier detect */ -#define SHADOW_DTR 0x01000000 /* data terminal ready */ -#define SHADOW_RTS 0x02000000 /* request to send */ -#define SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */ -#define SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */ -#define SHADOW_LOOP 0x10000000 /* loopback enabled */ - -/* bitmasks for IOC3_SRTR_ */ -#define SRTR_CNT 0x00000fff /* reload value for RX timer */ -#define SRTR_CNT_VAL 0x0fff0000 /* current value of RX timer */ -#define SRTR_CNT_VAL_SHIFT 16 -#define SRTR_HZ 16000 /* SRTR clock frequency */ - -/* bitmasks for IOC3_SIO_IR, IOC3_SIO_IEC and IOC3_SIO_IES */ -#define SIO_IR_SA_TX_MT 0x00000001 /* Serial port A TX empty */ -#define SIO_IR_SA_RX_FULL 0x00000002 /* port A RX buf full */ -#define SIO_IR_SA_RX_HIGH 0x00000004 /* port A RX hiwat */ -#define SIO_IR_SA_RX_TIMER 0x00000008 /* port A RX timeout */ -#define SIO_IR_SA_DELTA_DCD 0x00000010 /* port A delta DCD */ -#define SIO_IR_SA_DELTA_CTS 0x00000020 /* port A delta CTS */ -#define SIO_IR_SA_INT 0x00000040 /* port A pass-thru intr */ -#define SIO_IR_SA_TX_EXPLICIT 0x00000080 /* port A explicit TX thru */ -#define SIO_IR_SA_MEMERR 0x00000100 /* port A PCI error */ -#define SIO_IR_SB_TX_MT 0x00000200 /* */ -#define SIO_IR_SB_RX_FULL 0x00000400 /* */ -#define SIO_IR_SB_RX_HIGH 0x00000800 /* */ -#define SIO_IR_SB_RX_TIMER 0x00001000 /* */ -#define SIO_IR_SB_DELTA_DCD 0x00002000 /* */ -#define SIO_IR_SB_DELTA_CTS 0x00004000 /* */ -#define SIO_IR_SB_INT 0x00008000 /* */ -#define SIO_IR_SB_TX_EXPLICIT 0x00010000 /* */ -#define SIO_IR_SB_MEMERR 0x00020000 /* */ -#define SIO_IR_PP_INT 0x00040000 /* P port pass-thru intr */ -#define SIO_IR_PP_INTA 0x00080000 /* PP context A thru */ -#define SIO_IR_PP_INTB 0x00100000 /* PP context B thru */ -#define SIO_IR_PP_MEMERR 0x00200000 /* PP PCI error */ -#define SIO_IR_KBD_INT 0x00400000 /* kbd/mouse intr */ -#define SIO_IR_RT_INT 0x08000000 /* RT output pulse */ -#define SIO_IR_GEN_INT1 0x10000000 /* RT input pulse */ -#define SIO_IR_GEN_INT_SHIFT 28 - -/* per device interrupt masks */ -#define SIO_IR_SA (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) -#define SIO_IR_SB (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) -#define SIO_IR_PP (SIO_IR_PP_INT | SIO_IR_PP_INTA | \ - SIO_IR_PP_INTB | SIO_IR_PP_MEMERR) -#define SIO_IR_RT (SIO_IR_RT_INT | SIO_IR_GEN_INT1) - -/* macro to load pending interrupts */ -#define IOC3_PENDING_INTRS(mem) (PCI_INW(&((mem)->sio_ir)) & \ - PCI_INW(&((mem)->sio_ies_ro))) - -/* bitmasks for SIO_CR */ -#define SIO_CR_SIO_RESET 0x00000001 /* reset the SIO */ -#define SIO_CR_SER_A_BASE 0x000000fe /* DMA poll addr port A */ -#define SIO_CR_SER_A_BASE_SHIFT 1 -#define SIO_CR_SER_B_BASE 0x00007f00 /* DMA poll addr port B */ -#define SIO_CR_SER_B_BASE_SHIFT 8 -#define SIO_SR_CMD_PULSE 0x00078000 /* byte bus strobe length */ -#define SIO_CR_CMD_PULSE_SHIFT 15 -#define SIO_CR_ARB_DIAG 0x00380000 /* cur !enet PCI requet (ro) */ -#define SIO_CR_ARB_DIAG_TXA 0x00000000 -#define SIO_CR_ARB_DIAG_RXA 0x00080000 -#define SIO_CR_ARB_DIAG_TXB 0x00100000 -#define SIO_CR_ARB_DIAG_RXB 0x00180000 -#define SIO_CR_ARB_DIAG_PP 0x00200000 -#define SIO_CR_ARB_DIAG_IDLE 0x00400000 /* 0 -> active request (ro) */ - -/* bitmasks for INT_OUT */ -#define INT_OUT_COUNT 0x0000ffff /* pulse interval timer */ -#define INT_OUT_MODE 0x00070000 /* mode mask */ -#define INT_OUT_MODE_0 0x00000000 /* set output to 0 */ -#define INT_OUT_MODE_1 0x00040000 /* set output to 1 */ -#define INT_OUT_MODE_1PULSE 0x00050000 /* send 1 pulse */ -#define INT_OUT_MODE_PULSES 0x00060000 /* send 1 pulse every interval */ -#define INT_OUT_MODE_SQW 0x00070000 /* toggle output every interval */ -#define INT_OUT_DIAG 0x40000000 /* diag mode */ -#define INT_OUT_INT_OUT 0x80000000 /* current state of INT_OUT */ - -/* time constants for INT_OUT */ -#define INT_OUT_NS_PER_TICK (30 * 260) /* 30 ns PCI clock, divisor=260 */ -#define INT_OUT_TICKS_PER_PULSE 3 /* outgoing pulse lasts 3 ticks */ -#define INT_OUT_US_TO_COUNT(x) /* convert uS to a count value */ \ - (((x) * 10 + INT_OUT_NS_PER_TICK / 200) * \ - 100 / INT_OUT_NS_PER_TICK - 1) -#define INT_OUT_COUNT_TO_US(x) /* convert count value to uS */ \ - (((x) + 1) * INT_OUT_NS_PER_TICK / 1000) -#define INT_OUT_MIN_TICKS 3 /* min period is width of pulse in "ticks" */ -#define INT_OUT_MAX_TICKS INT_OUT_COUNT /* largest possible count */ - -/* bitmasks for GPCR */ -#define GPCR_DIR 0x000000ff /* tristate pin input or output */ -#define GPCR_DIR_PIN(x) (1<<(x)) /* access one of the DIR bits */ -#define GPCR_EDGE 0x000f0000 /* extint edge or level sensitive */ -#define GPCR_EDGE_PIN(x) (1<<((x)+15)) /* access one of the EDGE bits */ - -/* values for GPCR */ -#define GPCR_INT_OUT_EN 0x00100000 /* enable INT_OUT to pin 0 */ -#define GPCR_MLAN_EN 0x00200000 /* enable MCR to pin 8 */ -#define GPCR_DIR_SERA_XCVR 0x00000080 /* Port A Transceiver select enable */ -#define GPCR_DIR_SERB_XCVR 0x00000040 /* Port B Transceiver select enable */ -#define GPCR_DIR_PHY_RST 0x00000020 /* ethernet PHY reset enable */ - -/* defs for some of the generic I/O pins */ -#define GPCR_PHY_RESET 0x20 /* pin is output to PHY reset */ -#define GPCR_UARTB_MODESEL 0x40 /* pin is output to port B mode sel */ -#define GPCR_UARTA_MODESEL 0x80 /* pin is output to port A mode sel */ - -#define GPPR_PHY_RESET_PIN 5 /* GIO pin controlling phy reset */ -#define GPPR_UARTB_MODESEL_PIN 6 /* GIO pin controlling uart b mode select */ -#define GPPR_UARTA_MODESEL_PIN 7 /* GIO pin controlling uart a mode select */ - -#define EMCR_DUPLEX 0x00000001 -#define EMCR_PROMISC 0x00000002 -#define EMCR_PADEN 0x00000004 -#define EMCR_RXOFF_MASK 0x000001f8 -#define EMCR_RXOFF_SHIFT 3 -#define EMCR_RAMPAR 0x00000200 -#define EMCR_BADPAR 0x00000800 -#define EMCR_BUFSIZ 0x00001000 -#define EMCR_TXDMAEN 0x00002000 -#define EMCR_TXEN 0x00004000 -#define EMCR_RXDMAEN 0x00008000 -#define EMCR_RXEN 0x00010000 -#define EMCR_LOOPBACK 0x00020000 -#define EMCR_ARB_DIAG 0x001c0000 -#define EMCR_ARB_DIAG_IDLE 0x00200000 -#define EMCR_RST 0x80000000 - -#define EISR_RXTIMERINT 0x00000001 -#define EISR_RXTHRESHINT 0x00000002 -#define EISR_RXOFLO 0x00000004 -#define EISR_RXBUFOFLO 0x00000008 -#define EISR_RXMEMERR 0x00000010 -#define EISR_RXPARERR 0x00000020 -#define EISR_TXEMPTY 0x00010000 -#define EISR_TXRTRY 0x00020000 -#define EISR_TXEXDEF 0x00040000 -#define EISR_TXLCOL 0x00080000 -#define EISR_TXGIANT 0x00100000 -#define EISR_TXBUFUFLO 0x00200000 -#define EISR_TXEXPLICIT 0x00400000 -#define EISR_TXCOLLWRAP 0x00800000 -#define EISR_TXDEFERWRAP 0x01000000 -#define EISR_TXMEMERR 0x02000000 -#define EISR_TXPARERR 0x04000000 - -#define ERCSR_THRESH_MASK 0x000001ff /* enet RX threshold */ -#define ERCSR_RX_TMR 0x40000000 /* simulation only */ -#define ERCSR_DIAG_OFLO 0x80000000 /* simulation only */ - -#define ERBR_ALIGNMENT 4096 -#define ERBR_L_RXRINGBASE_MASK 0xfffff000 - -#define ERBAR_BARRIER_BIT 0x0100 -#define ERBAR_RXBARR_MASK 0xffff0000 -#define ERBAR_RXBARR_SHIFT 16 - -#define ERCIR_RXCONSUME_MASK 0x00000fff - -#define ERPIR_RXPRODUCE_MASK 0x00000fff -#define ERPIR_ARM 0x80000000 - -#define ERTR_CNT_MASK 0x000007ff - -#define ETCSR_IPGT_MASK 0x0000007f -#define ETCSR_IPGR1_MASK 0x00007f00 -#define ETCSR_IPGR1_SHIFT 8 -#define ETCSR_IPGR2_MASK 0x007f0000 -#define ETCSR_IPGR2_SHIFT 16 -#define ETCSR_NOTXCLK 0x80000000 - -#define ETCDC_COLLCNT_MASK 0x0000ffff -#define ETCDC_DEFERCNT_MASK 0xffff0000 -#define ETCDC_DEFERCNT_SHIFT 16 - -#define ETBR_ALIGNMENT (64*1024) -#define ETBR_L_RINGSZ_MASK 0x00000001 -#define ETBR_L_RINGSZ128 0 -#define ETBR_L_RINGSZ512 1 -#define ETBR_L_TXRINGBASE_MASK 0xffffc000 - -#define ETCIR_TXCONSUME_MASK 0x0000ffff -#define ETCIR_IDLE 0x80000000 - -#define ETPIR_TXPRODUCE_MASK 0x0000ffff - -#define EBIR_TXBUFPROD_MASK 0x0000001f -#define EBIR_TXBUFCONS_MASK 0x00001f00 -#define EBIR_TXBUFCONS_SHIFT 8 -#define EBIR_RXBUFPROD_MASK 0x007fc000 -#define EBIR_RXBUFPROD_SHIFT 14 -#define EBIR_RXBUFCONS_MASK 0xff800000 -#define EBIR_RXBUFCONS_SHIFT 23 - -#define MICR_REGADDR_MASK 0x0000001f -#define MICR_PHYADDR_MASK 0x000003e0 -#define MICR_PHYADDR_SHIFT 5 -#define MICR_READTRIG 0x00000400 -#define MICR_BUSY 0x00000800 - -#define MIDR_DATA_MASK 0x0000ffff - -#define ERXBUF_IPCKSUM_MASK 0x0000ffff -#define ERXBUF_BYTECNT_MASK 0x07ff0000 -#define ERXBUF_BYTECNT_SHIFT 16 -#define ERXBUF_V 0x80000000 - -#define ERXBUF_CRCERR 0x00000001 /* aka RSV15 */ -#define ERXBUF_FRAMERR 0x00000002 /* aka RSV14 */ -#define ERXBUF_CODERR 0x00000004 /* aka RSV13 */ -#define ERXBUF_INVPREAMB 0x00000008 /* aka RSV18 */ -#define ERXBUF_LOLEN 0x00007000 /* aka RSV2_0 */ -#define ERXBUF_HILEN 0x03ff0000 /* aka RSV12_3 */ -#define ERXBUF_MULTICAST 0x04000000 /* aka RSV16 */ -#define ERXBUF_BROADCAST 0x08000000 /* aka RSV17 */ -#define ERXBUF_LONGEVENT 0x10000000 /* aka RSV19 */ -#define ERXBUF_BADPKT 0x20000000 /* aka RSV20 */ -#define ERXBUF_GOODPKT 0x40000000 /* aka RSV21 */ -#define ERXBUF_CARRIER 0x80000000 /* aka RSV22 */ - -#define ETXD_BYTECNT_MASK 0x000007ff /* total byte count */ -#define ETXD_INTWHENDONE 0x00001000 /* intr when done */ -#define ETXD_D0V 0x00010000 /* data 0 valid */ -#define ETXD_B1V 0x00020000 /* buf 1 valid */ -#define ETXD_B2V 0x00040000 /* buf 2 valid */ -#define ETXD_DOCHECKSUM 0x00080000 /* insert ip cksum */ -#define ETXD_CHKOFF_MASK 0x07f00000 /* cksum byte offset */ -#define ETXD_CHKOFF_SHIFT 20 - -#define ETXD_D0CNT_MASK 0x0000007f -#define ETXD_B1CNT_MASK 0x0007ff00 -#define ETXD_B1CNT_SHIFT 8 -#define ETXD_B2CNT_MASK 0x7ff00000 -#define ETXD_B2CNT_SHIFT 20 - -typedef enum ioc3_subdevs_e { - ioc3_subdev_ether, - ioc3_subdev_generic, - ioc3_subdev_nic, - ioc3_subdev_kbms, - ioc3_subdev_ttya, - ioc3_subdev_ttyb, - ioc3_subdev_ecpp, - ioc3_subdev_rt, - ioc3_nsubdevs -} ioc3_subdev_t; - -/* subdevice disable bits, - * from the standard INFO_LBL_SUBDEVS - */ -#define IOC3_SDB_ETHER (1< #include #include -#include +#include #include #include diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index 570098b..6997b1e 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index 42d6cb9..d3b995e 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/Makefile b/drivers/Makefile index 795d0ca..ad2225e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -123,7 +123,6 @@ obj-y += mmc/ obj-$(CONFIG_MEMSTICK) += memstick/ obj-y += 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/input/serio/Kconfig b/drivers/input/serio/Kconfig index c3d05b4..8826531 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -174,6 +174,14 @@ config SERIO_MACEPS2 To compile this driver as a module, choose M here: the module will be called maceps2. +config SERIO_SGI_IOC3 + tristate "SGI IOC3 PS/2 controller" + default y + depends on SGI_IOC3 + help + Say Y here if you have an SGI Octane or IOC3 PCI card and you + want to use its keyboard. + config SERIO_LIBPS2 tristate "PS/2 driver library" depends on SERIO_I8042 || SERIO_I8042=n diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 2374ef9..fdaaccb 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o +obj-$(CONFIG_SERIO_SGI_IOC3) += ioc3kbd.o obj-$(CONFIG_SERIO_LIBPS2) += libps2.o obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c new file mode 100644 index 0000000..a366c14 --- /dev/null +++ b/drivers/input/serio/ioc3kbd.c @@ -0,0 +1,176 @@ +/* + * SGI IOC3 PS/2 controller driver for linux + * + * Copyright (C) 2005 Stanislaw Skowronek + * 2009 Johannes Dickgreber + */ + +#include +#include +#include +#include +#include +#include + +#include + +struct ioc3kbd_data { + struct ioc3_driver_data *idd; + struct serio *kbd, *aux; +}; + +static int ioc3kbd_write(struct serio *dev, unsigned char val) +{ + struct ioc3kbd_data *d = (struct ioc3kbd_data *)(dev->port_data); + struct ioc3_driver_data *idd = d->idd; + unsigned mask; + unsigned long timeout = 0; + + mask = (dev == d->aux) ? KM_CSR_M_WRT_PEND : KM_CSR_K_WRT_PEND; + while ((readl(&idd->vma->km_csr) & mask) && (timeout < 1000)) { + udelay(100); + timeout++; + } + + if (dev == d->aux) + writel(((unsigned)val) & 0x000000ff, &idd->vma->m_wd); + else + writel(((unsigned)val) & 0x000000ff, &idd->vma->k_wd); + + if (timeout >= 1000) + return -1; + return 0; +} + +static int ioc3kbd_intr(struct ioc3_submodule *is, + struct ioc3_driver_data *idd, unsigned int irq) +{ + struct ioc3kbd_data *d = (struct ioc3kbd_data *)(idd->data[is->id]); + unsigned int data_k, data_m; + + ioc3_ack(is, idd, irq); + data_k = readl(&idd->vma->k_rd); + data_m = readl(&idd->vma->m_rd); + + if (data_k & KM_RD_VALID_0) + serio_interrupt(d->kbd, + (data_k >> KM_RD_DATA_0_SHIFT) & 0xff, 0); + if (data_k & KM_RD_VALID_1) + serio_interrupt(d->kbd, + (data_k >> KM_RD_DATA_1_SHIFT) & 0xff, 0); + if (data_k & KM_RD_VALID_2) + serio_interrupt(d->kbd, + (data_k >> KM_RD_DATA_2_SHIFT) & 0xff, 0); + if (data_m & KM_RD_VALID_0) + serio_interrupt(d->aux, + (data_m >> KM_RD_DATA_0_SHIFT) & 0xff, 0); + if (data_m & KM_RD_VALID_1) + serio_interrupt(d->aux, + (data_m >> KM_RD_DATA_1_SHIFT) & 0xff, 0); + if (data_m & KM_RD_VALID_2) + serio_interrupt(d->aux, + (data_m >> KM_RD_DATA_2_SHIFT) & 0xff, 0); + + return 0; +} + +static int ioc3kbd_open(struct serio *dev) +{ + return 0; +} + +static void ioc3kbd_close(struct serio *dev) +{ + /* Empty */ +} + +static struct ioc3kbd_data *ioc3kbd_allocate_port(int idx, + struct ioc3_driver_data *idd) +{ + struct serio *sk, *sa; + struct ioc3kbd_data *d; + + sk = devm_kzalloc(&idd->pdev->dev, sizeof(struct serio), GFP_KERNEL); + sa = devm_kzalloc(&idd->pdev->dev, sizeof(struct serio), GFP_KERNEL); + d = devm_kzalloc(&idd->pdev->dev, sizeof(struct ioc3kbd_data), + GFP_KERNEL); + + if (sk && sa && d) { + sk->id.type = SERIO_8042; + sk->write = ioc3kbd_write; + sk->open = ioc3kbd_open; + sk->close = ioc3kbd_close; + snprintf(sk->name, sizeof(sk->name), "IOC3 keyboard %d", idx); + snprintf(sk->phys, sizeof(sk->phys), "ioc3/serio%dkbd", idx); + sk->port_data = d; + sk->dev.parent = &idd->pdev->dev; + + sa->id.type = SERIO_8042; + sa->write = ioc3kbd_write; + sa->open = ioc3kbd_open; + sa->close = ioc3kbd_close; + snprintf(sa->name, sizeof(sa->name), "IOC3 auxiliary %d", idx); + snprintf(sa->phys, sizeof(sa->phys), "ioc3/serio%daux", idx); + sa->port_data = d; + sa->dev.parent = &idd->pdev->dev; + + d->idd = idd; + d->kbd = sk; + d->aux = sa; + return d; + } + + return NULL; +} + +static int ioc3kbd_probe(struct ioc3_submodule *is, + struct ioc3_driver_data *idd) +{ + struct ioc3kbd_data *d; + + if ((idd->class != IOC3_CLASS_BASE_IP30) && + (idd->class != IOC3_CLASS_CADDUO)) + return 1; + + d = ioc3kbd_allocate_port(idd->id, idd); + if (!d) + return 1; + + idd->data[is->id] = d; + ioc3_enable(is, idd, is->irq_mask); + serio_register_port(d->kbd); + serio_register_port(d->aux); + + return 0; +} + +static int ioc3kbd_remove(struct ioc3_submodule *is, + struct ioc3_driver_data *idd) +{ + struct ioc3kbd_data *d = (struct ioc3kbd_data *)(idd->data[is->id]); + + ioc3_disable(is, idd, is->irq_mask); + serio_unregister_port(d->kbd); + serio_unregister_port(d->aux); + idd->data[is->id] = NULL; + + return 0; +} + +static struct ioc3_submodule ioc3kbd_driver = { + .name = "serio", + .probe = ioc3kbd_probe, + .remove = ioc3kbd_remove, + .irq_mask = SIO_IR_KBD_INT, + .reset_mask = 1, + .intr = ioc3kbd_intr, + .owner = THIS_MODULE, +}; + +ioc3_submodule_driver(ioc3kbd_driver); + +MODULE_AUTHOR("Stanislaw Skowronek "); +MODULE_DESCRIPTION("SGI IOC3 serio driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("R27"); + diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 22892c7..b33a03e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -138,6 +138,18 @@ config INTEL_MID_PTI an Intel Atom (non-netbook) mobile device containing a MIPI P1149.7 standard implementation. +config SGI_IOC3 + tristate "SGI IOC3 Base IO support" + depends on PCI + ---help--- + This option enables basic support for the SGI IOC3-based BaseIO + 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, Origin, Octane, or a PCI IOC3 card, + then say Y. Otherwise say N. + config SGI_IOC4 tristate "SGI IOC4 Base IO support" depends on PCI diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 537d7f3..941bcec 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o +obj-$(CONFIG_SGI_IOC3) += ioc3.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o diff --git a/drivers/misc/ioc3.c b/drivers/misc/ioc3.c new file mode 100644 index 0000000..89852f3 --- /dev/null +++ b/drivers/misc/ioc3.c @@ -0,0 +1,939 @@ +/* + * SGI IOC3 master driver and IRQ demuxer + * + * Copyright (c) 2005 Stanislaw Skowronek + * Copyright (c) 2011-2014 Joshua Kinard (fixes, upkeep) + * Heavily based on similar work by: + * Brent Casavant - IOC4 master driver + * Pat Gefre - IOC3 serial port IRQ demuxer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IOC3_PCI_SIZE 0x100000 + +/* Ethernet submodule is always 0 */ +#define ETH_ID 0 + +static DECLARE_RWSEM(ioc3_devices_rwsem); +static DEFINE_RWLOCK(ioc3_subm_lock); +static LIST_HEAD(ioc3_devices); +static struct ioc3_submodule *ioc3_subm[IOC3_MAX_SUBMODULES]; +static int ioc3_counter; + +/* ----------------------------------------------------------------------- */ +/* NIC probing code */ + +static inline u32 +mcr_pack(u32 pulse, u32 sample) +{ + return ((pulse << 10) | (sample << 2)); +} + +static int +ioc3_nic_wait(struct ioc3_driver_data *idd) +{ + u32 mcr; + + do { + mcr = readl(&idd->vma->mcr); + } while (!(mcr & 2)); + + return (mcr & 1); +} + +static int +ioc3_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 = ioc3_nic_wait(idd); + local_irq_restore(flags); + + udelay(500); + + return presence; +} + +static int +ioc3_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 = ioc3_nic_wait(idd); + local_irq_restore(flags); + + udelay(500); + + return result; +} + +static void +ioc3_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); + + ioc3_nic_wait(idd); +} + +static u32 +ioc3_nic_read_byte(struct ioc3_driver_data *idd) +{ + u32 result = 0; + int i; + + for (i = 0; i < 8; i++) + result = ((result >> 1) | (ioc3_nic_read_bit(idd) << 7)); + + return result; +} + +static void +ioc3_nic_write_byte(struct ioc3_driver_data *idd, int byte) +{ + int i, bit; + + for (i = 8; i; i--) { + bit = (byte & 1); + byte >>= 1; + + ioc3_nic_write_bit(idd, bit); + } +} + +static unsigned long +ioc3_nic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr) +{ + int a, b, index, disc; + + ioc3_nic_reset(idd); + + /* Search ROM. */ + ioc3_nic_write_byte(idd, 0xf0); + + /* Algorithm from ``Book of iButton Standards''. */ + for (index = 0, disc = 0; index < 64; index++) { + a = ioc3_nic_read_bit(idd); + b = ioc3_nic_read_bit(idd); + + if (unlikely(a && b)) { + pr_warn("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; + ioc3_nic_write_bit(idd, (addr >> index) & 1); + continue; + } else { + if (a) + addr |= (1UL << index); + else + addr &= ~(1UL << index); + ioc3_nic_write_bit(idd, a); + continue; + } + } + *last = disc; + return addr; +} + +static void +ioc3_nic_addr(struct ioc3_driver_data *idd, unsigned long addr) +{ + int index; + + ioc3_nic_reset(idd); + ioc3_nic_write_byte(idd, 0xf0); + + for (index = 0; index < 64; index++) { + ioc3_nic_read_bit(idd); + ioc3_nic_read_bit(idd); + ioc3_nic_write_bit(idd, ((addr >> index) & 1)); + } +} + +static void +crc16_byte(u32 *crc, u8 db) +{ + int i; + + for (i = 0; i < 8; i++) { + *crc <<= 1; + if ((db ^ (*crc >> 16)) & 1) + *crc ^= 0x8005; + db >>= 1; + } + *crc &= 0xffff; +} + +static u32 +crc16_area(u8 *dbs, int size, u32 crc) +{ + while (size--) + crc16_byte(&crc, *(dbs++)); + + return crc; +} + +static void +crc8_byte(u32 *crc, u8 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 u32 +crc8_addr(unsigned long addr) +{ + int i; + u32 crc = 0x00; + + for (i = 0; i < 8; i++) + crc8_byte(&crc, addr >> (i << 3)); + return crc; +} + +static void +ioc3_read_redir_page(struct ioc3_driver_data *idd, unsigned long addr, + int page, u8 *redir, u8 *data) +{ + int loops = 16, i; + + while (redir[page] != 0xff) { + page = (redir[page] ^ 0xff); + loops--; + if (unlikely(loops < 0)) { + pr_err("ioc3: NIC circular redirection\n"); + return; + } + } + + loops = 3; + while (loops > 0) { + ioc3_nic_addr(idd, addr); + ioc3_nic_write_byte(idd, 0xf0); + ioc3_nic_write_byte(idd, (page << 5) & 0xe0); + ioc3_nic_write_byte(idd, (page >> 3) & 0x1f); + + for (i = 0; i < 0x20; i++) + data[i] = ioc3_nic_read_byte(idd); + + if (crc16_area(data, 0x20, 0x0000) == 0x800d) + return; + + loops--; + } + + pr_err("ioc3: CRC error in data page\n"); + for (i = 0; i < 0x20; i++) + data[i] = 0x00; +} + +static void +ioc3_read_redir_map(struct ioc3_driver_data *idd, unsigned long addr, + u8 *redir) +{ + int i, j, crc_ok, loops = 3; + u32 crc; + + while (loops > 0) { + crc_ok = 1; + ioc3_nic_addr(idd, addr); + ioc3_nic_write_byte(idd, 0xaa); + ioc3_nic_write_byte(idd, 0x00); + ioc3_nic_write_byte(idd, 0x01); + + for (i = 0; i < 64; i += 8) { + for (j = 0; j < 8; j++) + redir[i + j] = ioc3_nic_read_byte(idd); + + crc = crc16_area(redir + i, 8, + ((i == 0) ? 0x8707 : 0x0000)); + + crc16_byte(&crc, ioc3_nic_read_byte(idd)); + crc16_byte(&crc, ioc3_nic_read_byte(idd)); + + if (crc != 0x800d) + crc_ok = 0; + } + if (crc_ok) + return; + loops--; + } + pr_err("ioc3: CRC error in redirection page\n"); + for (i = 0; i < 64; i++) + redir[i] = 0xff; +} + +static void +ioc3_read_nic(struct ioc3_driver_data *idd, unsigned long addr) +{ + u8 redir[64]; + u8 data[64], part[32]; + int i, j; + + /* Read redirections */ + ioc3_read_redir_map(idd, addr, redir); + + /* Read data pages */ + ioc3_read_redir_page(idd, addr, 0, redir, data); + ioc3_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 (IP30) power supplies */ + if (!(strncmp(part, "060-0035-", 9)) || + !(strncmp(part, "060-0038-", 9)) || + !(strncmp(part, "060-0028-", 9))) + return; + + strlcpy(idd->nic_part, part, sizeof(idd->nic_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 +ioc3_read_mac(struct ioc3_driver_data *idd, unsigned long addr) +{ + int i, loops = 3; + u8 data[13]; + + while (loops > 0) { + ioc3_nic_addr(idd, addr); + ioc3_nic_write_byte(idd, 0xf0); + ioc3_nic_write_byte(idd, 0x00); + ioc3_nic_write_byte(idd, 0x00); + ioc3_nic_read_byte(idd); + + for (i = 0; i < 13; i++) + data[i] = ioc3_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--; + } + + pr_err("ioc3: CRC error in MAC address\n"); + for (i = 0; i < 6; i++) + idd->nic_mac[i] = 0x00; +} + +static void +ioc3_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; + first = ioc3_nic_find(idd, &save, 0); + addr = first; + + if (unlikely(!first)) + return; + + while (1) { + if (crc8_addr(addr)) + break; + else { + switch (addr & 0xff) { + case 0x0b: + ioc3_read_nic(idd, addr); + break; + case 0x09: + case 0x89: + case 0x91: + ioc3_read_mac(idd, addr); + break; + } + } + + addr = ioc3_nic_find(idd, &save, addr); + if (addr == first) + return; + } + loops--; + } + pr_err("ioc3: CRC error in NIC address\n"); +} +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ +/* Interrupt handling */ + +void +ioc3_write_sio_ireg(struct ioc3_driver_data *idd, uint32_t value, int reg) +{ + unsigned long flags; + + spin_lock_irqsave(&idd->ir_lock, flags); + switch (reg) { + case IOC3_W_IES: + writel(value, &idd->vma->sio_ies); + break; + case IOC3_W_IEC: + writel(value, &idd->vma->sio_iec); + break; + } + spin_unlock_irqrestore(&idd->ir_lock, flags); +} + +static inline u32 +get_pending_intrs(struct ioc3_driver_data *idd) +{ + u32 intrs = 0; + unsigned long flags; + + spin_lock_irqsave(&idd->ir_lock, flags); + intrs = readl(&idd->vma->sio_ir); + intrs &= readl(&idd->vma->sio_ies); + spin_unlock_irqrestore(&idd->ir_lock, flags); + + return intrs; +} + +static irqreturn_t +ioc3_intr_io(int irq, void *arg) +{ + u32 pending; + int i, pending_sub, ret, handled = 1; + unsigned long flags; + struct ioc3_driver_data *idd = arg; + + read_lock_irqsave(&ioc3_subm_lock, flags); + /* Send Ethernet IRQ to the driver */ + if (idd->active[ETH_ID] && !idd->dual_irq) + if (readl(&idd->vma->eisr)) + handled = !ioc3_subm[ETH_ID]->intr(ioc3_subm[ETH_ID], + idd, 0); + + /* Look at the I/O IRQs */ + pending = get_pending_intrs(idd); + for (i = 1; i < IOC3_MAX_SUBMODULES; i++) { + if (!idd->active[i]) + continue; + + /* Check for pending interrupts from specific submodule. */ + pending_sub = (pending & ioc3_subm[i]->irq_mask); + if (!pending_sub) + continue; + + /* Clear interrupt */ + ioc3_write_sio_ireg(idd, ioc3_subm[i]->irq_mask, + IOC3_W_IEC); + + /* Call submodule interrupt, if defined. */ + if (ioc3_subm[i]->intr) { + ret = ioc3_subm[i]->intr(ioc3_subm[i], idd, + pending_sub); + if (!ret) { + pending &= ~ioc3_subm[i]->irq_mask; + handled = 1; + } + } + + /* If .reset_mask is true, then re-enable the interrupt. */ + if (ioc3_subm[i]->reset_mask) + ioc3_write_sio_ireg(idd, ioc3_subm[i]->irq_mask, + IOC3_W_IES); + } + read_unlock_irqrestore(&ioc3_subm_lock, flags); + + if (pending) { + pr_warn("ioc3: Pending IRQs 0x%08x discarded and disabled\n", + pending); + ioc3_write_sio_ireg(idd, pending, IOC3_W_IEC); + handled = 1; + } + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static irqreturn_t +ioc3_intr_eth(int irq, void *arg) +{ + int handled = 0; + unsigned long flags; + struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg; + + read_lock_irqsave(&ioc3_subm_lock, flags); + if (idd->active[ETH_ID] && idd->dual_irq) + handled = !ioc3_subm[ETH_ID]-> + intr(ioc3_subm[ETH_ID], idd, 0); + read_unlock_irqrestore(&ioc3_subm_lock, flags); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +void +ioc3_enable(struct ioc3_submodule *is, struct ioc3_driver_data *idd, u32 irqs) +{ + ioc3_write_sio_ireg(idd, irqs & is->irq_mask, IOC3_W_IES); +} +EXPORT_SYMBOL_GPL(ioc3_enable); + +void +ioc3_ack(struct ioc3_submodule *is, struct ioc3_driver_data *idd, u32 irqs) +{ + writel(irqs & is->irq_mask, &idd->vma->sio_ir); +} +EXPORT_SYMBOL_GPL(ioc3_ack); + +void +ioc3_disable(struct ioc3_submodule *is, struct ioc3_driver_data *idd, u32 irqs) +{ + ioc3_write_sio_ireg(idd, irqs & is->irq_mask, IOC3_W_IEC); +} +EXPORT_SYMBOL_GPL(ioc3_disable); +/* ----------------------------------------------------------------------- */ + + + +/* ----------------------------------------------------------------------- */ +/* Misc functions */ +void +ioc3_gpcr_set(struct ioc3_driver_data *idd, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&idd->gpio_lock, flags); + writel(val, &idd->vma->gpcr_s); + spin_unlock_irqrestore(&idd->gpio_lock, flags); +} +EXPORT_SYMBOL_GPL(ioc3_gpcr_set); + +/* IP27, IP30 writes to gpdr to set GPIOs to 1 */ +/* XXX: Kill this soon. Octane LED driver still uses it. */ +void +ioc3_gpio(struct ioc3_driver_data *idd, u32 mask, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&idd->gpio_lock, flags); + idd->gpdr_shadow &= ~mask; + idd->gpdr_shadow |= (val & mask); + writel(idd->gpdr_shadow, &idd->vma->gpdr); + spin_unlock_irqrestore(&idd->gpio_lock, flags); +} +EXPORT_SYMBOL_GPL(ioc3_gpio); + +/* Keep it simple, stupid! */ +static inline int +find_slot(void **tab, int max) +{ + int i; + + for (i = 1; i < max; i++) + if (!(tab[i])) + return i; + + return -1; +} +/* ----------------------------------------------------------------------- */ + + + +/* ----------------------------------------------------------------------- */ +/* IOC3 submodule reg/unreg */ + +int +ioc3_register_submodule(struct ioc3_submodule *is) +{ + struct ioc3_driver_data *idd; + int alloc_id; + unsigned long flags; + + write_lock_irqsave(&ioc3_subm_lock, flags); + if (is->ethernet) + if (ioc3_subm[ETH_ID] == NULL) + alloc_id = ETH_ID; + else + alloc_id = -2; + else + alloc_id = find_slot((void **)ioc3_subm, IOC3_MAX_SUBMODULES); + + if (alloc_id >= 0) + ioc3_subm[alloc_id] = is; + write_unlock_irqrestore(&ioc3_subm_lock, flags); + + if (alloc_id == -1) { + pr_warn("ioc3: Increase IOC3_MAX_SUBMODULES!\n"); + return -ENOMEM; + } + + if (alloc_id == -2) { + pr_warn("ioc3: Ethernet module already registered~\n"); + return -ENODEV; + } + + 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; +} +EXPORT_SYMBOL_GPL(ioc3_register_submodule); + +void +ioc3_unregister_submodule(struct ioc3_submodule *is) +{ + struct ioc3_driver_data *idd; + unsigned long flags; + + write_lock_irqsave(&ioc3_subm_lock, flags); + if (ioc3_subm[is->id] == is) + ioc3_subm[is->id] = NULL; + else + pr_warn("ioc3: submodule %s has wrong ID.\n", is->name); + write_unlock_irqrestore(&ioc3_subm_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]) + continue; + + if (is->remove) + if (is->remove(is, idd)) + pr_warn("ioc3: submodule %s remove failed " + "for pci_dev %s.\n", + module_name(is->owner), + pci_name(idd->pdev)); + idd->active[is->id] = 0; + if (is->irq_mask) + ioc3_write_sio_ireg(idd, is->irq_mask, IOC3_W_IEC); + } + up_read(&ioc3_devices_rwsem); +} +EXPORT_SYMBOL_GPL(ioc3_unregister_submodule); +/* ----------------------------------------------------------------------- */ + + + +/* ----------------------------------------------------------------------- */ +/* Device management */ + +static char +*ioc3_class_names[] = { + "Unknown", + "IP27 BaseIO", + "IP30 System Board", + "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 the IOC3 part info */ + pr_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; + int ret = -ENODEV, id; + + /* Enable IOC3 and take ownership of it */ + if (pci_enable_device(pdev)) { + pr_warn("ioc3: Failed to enable pci_dev %s.\n", + pci_name(pdev)); + goto out; + } + + if (pci_request_regions(pdev, "ioc3")) { + pr_warn("ioc3: Unable to request region for pci_dev %s.\n", + pci_name(pdev)); + goto out_disable_dev; + } + + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); + 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) + pr_warn("ioc3: Unable to obtain 64 bit DMA for " + "consistent allocations\n"); + } +#endif + + /* Set up per-IOC3 data */ + idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL); + if (!idd) { + pr_warn("ioc3: Failed to allocate data for pci_dev %s.\n", + pci_name(pdev)); + ret = -ENOMEM; + goto out_release_regions; + } + 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->vma = pci_ioremap_bar(pdev, 0); + if (!idd->vma) { + pr_warn("ioc3: Unable to remap PCI BAR for %s.\n", + pci_name(pdev)); + goto out_free_idd; + } + + /* 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); + + ioc3_probe_nic(idd); + + idd->class = ioc3_class(idd); + + /* Clear IRQs */ + ioc3_write_sio_ireg(idd, ~0, IOC3_W_IEC); + writel(~0, &idd->vma->sio_ir); + + /* Set up IRQs */ + switch (idd->class) { + case IOC3_CLASS_BASE_IP27: + case IOC3_CLASS_BASE_IP30: + 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 + pr_warn("ioc3: request_irq fails for IRQ 0x%x\n", + pdev->irq); + + if (!request_irq((pdev->irq + 2), ioc3_intr_io, IRQF_SHARED, + "ioc3-io", (void *)idd)) + idd->irq_io = (pdev->irq + 2); + else + pr_warn("ioc3: request_irq fails for IRQ 0x%x\n", + (pdev->irq + 2)); + break; + default: + if (!request_irq(pdev->irq, ioc3_intr_io, IRQF_SHARED, + "ioc3", (void *)idd)) + idd->irq_io = pdev->irq; + else + pr_warn("ioc3: request_irq fails for IRQ 0x%x\n", + pdev->irq); + } + + /* Add this IOC3 to all submodules */ + for (id = 0; id < IOC3_MAX_SUBMODULES; id++) + if (ioc3_subm[id] && ioc3_subm[id]->probe) { + /* Set to 1 for IRQs in probe */ + idd->active[id] = 1; + idd->active[id] = !ioc3_subm[id]->probe(ioc3_subm[id], + idd); + } + + pr_info("IOC3 Master Driver loaded for %s\n", pci_name(pdev)); + + return 0; + +out_free_idd: + kfree(idd); + +out_release_regions: + pci_release_regions(pdev); + +out_disable_dev: + 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]) + continue; + + if (ioc3_subm[id] && ioc3_subm[id]->remove) + if (ioc3_subm[id]->remove(ioc3_subm[id], idd)) + pr_warn("ioc3: submodule 0x%s remove failed " + "for pci_dev %s.\n", + module_name(ioc3_subm[id]->owner), + pci_name(pdev)); + idd->active[id] = 0; + } + + /* Clear and disable all IRQs */ + ioc3_write_sio_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); + pci_release_regions(pdev); + + /* 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, 0, 0}, + {0,}, +}; +MODULE_DEVICE_TABLE(pci, ioc3_id_table); + +static struct +pci_driver ioc3_driver = { + .name = "IOC3", + .id_table = ioc3_id_table, + .probe = ioc3_probe, + .remove = ioc3_remove, +}; +/* ----------------------------------------------------------------------- */ + + + +/* ----------------------------------------------------------------------- */ +/* Module management */ + +static int __init +ioc3_init(void) +{ + return pci_register_driver(&ioc3_driver); +} + +static void __exit +ioc3_exit(void) +{ + pci_unregister_driver(&ioc3_driver); +} +/* ----------------------------------------------------------------------- */ + + +module_init(ioc3_init); +module_exit(ioc3_exit); + +MODULE_AUTHOR("Stanislaw Skowronek "); +MODULE_AUTHOR("Joshua Kinard "); +MODULE_DESCRIPTION("SGI IOC3 PCI driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/net/ethernet/sgi/Kconfig b/drivers/net/ethernet/sgi/Kconfig index fbbb21c..e304e4f 100644 --- a/drivers/net/ethernet/sgi/Kconfig +++ b/drivers/net/ethernet/sgi/Kconfig @@ -18,7 +18,7 @@ if NET_VENDOR_SGI config SGI_IOC3_ETH bool "SGI IOC3 Ethernet" - depends on PCI && SGI_IP27 + depends on PCI && SGI_IOC3 select CRC32 select MII ---help--- diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 067384c..708e7c7 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -7,6 +7,8 @@ * * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc. + * Copyright (C) 2005 Stanislaw Skowronek (port to meta-driver) + * 2009 Johannes Dickgreber * * References: * o IOC3 ASIC specification 4.51, 1996-04-18 @@ -20,79 +22,72 @@ * o Use prefetching for large packets. What is a good lower limit for * prefetching? * o We're probably allocating a bit too much memory. - * o Use hardware checksums. - * o Convert to using a IOC3 meta driver. * o Which PHYs might possibly be attached to the IOC3 in real live, * which workarounds are required for them? Do we ever have Lucent's? * o For the 2.5 branch kill the mii-tool ioctls. */ #define IOC3_NAME "ioc3-eth" -#define IOC3_VERSION "2.6.3-4" +#define IOC3_VERSION "0.42-meta" +#include + +#include #include +#include +#include +#include #include -#include -#include -#include -#include -#include #include -#include -#include +#include #include #include -#include +#include #include -#ifdef CONFIG_SERIAL_8250 -#include -#include -#include -#endif - -#include -#include -#include -#include -#include +#include -#include -#include -#include -#include -#include -#include #include -/* - * 64 RX buffers. This is tunable in the range of 16 <= x < 512. The - * value must be a power of two. +#define IOC3_CACHELINE 128UL + +/* 64 RX buffers. This is tunable in the range of 16 <= x <= 512. + * The value must be a power of two. + */ +#define RX_BUFFS 512 +#define RX_MASK (RX_BUFFS - 1) +/* 128 TX buffer not tunable + */ +#define TX_BUFFS 128 +#define TX_MASK (TX_BUFFS - 1) +/* BEWARE: The IOC3 documentation documents the size of rx buffers as + * 1644 while it's actually 1664. This one was nasty to track down ... */ -#define RX_BUFFS 64 +#define RX_OFFSET 18 +#define RX_BUF_ALLOC_SIZE 1664 -#define ETCSR_FD ((17<data); if (offset) skb_reserve(skb, offset); + skb->dev = dev; } return skb; } -static inline unsigned long ioc3_map(void *ptr, unsigned long vdev) +static unsigned long ioc3_map(void *ptr, unsigned long dma_attr) { #ifdef CONFIG_SGI_IP27 - vdev <<= 57; /* Shift to PCI64_ATTR_VIRTUAL */ - - return vdev | (0xaUL << PCI64_ATTR_TARG_SHFT) | PCI64_ATTR_PREF | - ((unsigned long)ptr & TO_PHYS_MASK); + return ((0xaUL << PCI64_ATTR_TARG_SHFT) | dma_attr | + ((unsigned long)ptr & TO_PHYS_MASK)); #else return virt_to_bus(ptr); #endif @@ -150,368 +129,136 @@ static inline unsigned long ioc3_map(void *ptr, unsigned long vdev) /* BEWARE: The IOC3 documentation documents the size of rx buffers as 1644 while it's actually 1664. This one was nasty to track down ... */ -#define RX_OFFSET 10 -#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET + IOC3_CACHELINE) - -/* DMA barrier to separate cached and uncached accesses. */ -#define BARRIER() \ - __asm__("sync" ::: "memory") - - -#define IOC3_SIZE 0x100000 - -/* - * IOC3 is a big endian device - * - * Unorthodox but makes the users of these macros more readable - the pointer - * to the IOC3's memory mapped registers is expected as struct ioc3 * ioc3 - * in the environment. - */ -#define ioc3_r_mcr() be32_to_cpu(ioc3->mcr) -#define ioc3_w_mcr(v) do { ioc3->mcr = cpu_to_be32(v); } while (0) -#define ioc3_w_gpcr_s(v) do { ioc3->gpcr_s = cpu_to_be32(v); } while (0) -#define ioc3_r_emcr() be32_to_cpu(ioc3->emcr) -#define ioc3_w_emcr(v) do { ioc3->emcr = cpu_to_be32(v); } while (0) -#define ioc3_r_eisr() be32_to_cpu(ioc3->eisr) -#define ioc3_w_eisr(v) do { ioc3->eisr = cpu_to_be32(v); } while (0) -#define ioc3_r_eier() be32_to_cpu(ioc3->eier) -#define ioc3_w_eier(v) do { ioc3->eier = cpu_to_be32(v); } while (0) -#define ioc3_r_ercsr() be32_to_cpu(ioc3->ercsr) -#define ioc3_w_ercsr(v) do { ioc3->ercsr = cpu_to_be32(v); } while (0) -#define ioc3_r_erbr_h() be32_to_cpu(ioc3->erbr_h) -#define ioc3_w_erbr_h(v) do { ioc3->erbr_h = cpu_to_be32(v); } while (0) -#define ioc3_r_erbr_l() be32_to_cpu(ioc3->erbr_l) -#define ioc3_w_erbr_l(v) do { ioc3->erbr_l = cpu_to_be32(v); } while (0) -#define ioc3_r_erbar() be32_to_cpu(ioc3->erbar) -#define ioc3_w_erbar(v) do { ioc3->erbar = cpu_to_be32(v); } while (0) -#define ioc3_r_ercir() be32_to_cpu(ioc3->ercir) -#define ioc3_w_ercir(v) do { ioc3->ercir = cpu_to_be32(v); } while (0) -#define ioc3_r_erpir() be32_to_cpu(ioc3->erpir) -#define ioc3_w_erpir(v) do { ioc3->erpir = cpu_to_be32(v); } while (0) -#define ioc3_r_ertr() be32_to_cpu(ioc3->ertr) -#define ioc3_w_ertr(v) do { ioc3->ertr = cpu_to_be32(v); } while (0) -#define ioc3_r_etcsr() be32_to_cpu(ioc3->etcsr) -#define ioc3_w_etcsr(v) do { ioc3->etcsr = cpu_to_be32(v); } while (0) -#define ioc3_r_ersr() be32_to_cpu(ioc3->ersr) -#define ioc3_w_ersr(v) do { ioc3->ersr = cpu_to_be32(v); } while (0) -#define ioc3_r_etcdc() be32_to_cpu(ioc3->etcdc) -#define ioc3_w_etcdc(v) do { ioc3->etcdc = cpu_to_be32(v); } while (0) -#define ioc3_r_ebir() be32_to_cpu(ioc3->ebir) -#define ioc3_w_ebir(v) do { ioc3->ebir = cpu_to_be32(v); } while (0) -#define ioc3_r_etbr_h() be32_to_cpu(ioc3->etbr_h) -#define ioc3_w_etbr_h(v) do { ioc3->etbr_h = cpu_to_be32(v); } while (0) -#define ioc3_r_etbr_l() be32_to_cpu(ioc3->etbr_l) -#define ioc3_w_etbr_l(v) do { ioc3->etbr_l = cpu_to_be32(v); } while (0) -#define ioc3_r_etcir() be32_to_cpu(ioc3->etcir) -#define ioc3_w_etcir(v) do { ioc3->etcir = cpu_to_be32(v); } while (0) -#define ioc3_r_etpir() be32_to_cpu(ioc3->etpir) -#define ioc3_w_etpir(v) do { ioc3->etpir = cpu_to_be32(v); } while (0) -#define ioc3_r_emar_h() be32_to_cpu(ioc3->emar_h) -#define ioc3_w_emar_h(v) do { ioc3->emar_h = cpu_to_be32(v); } while (0) -#define ioc3_r_emar_l() be32_to_cpu(ioc3->emar_l) -#define ioc3_w_emar_l(v) do { ioc3->emar_l = cpu_to_be32(v); } while (0) -#define ioc3_r_ehar_h() be32_to_cpu(ioc3->ehar_h) -#define ioc3_w_ehar_h(v) do { ioc3->ehar_h = cpu_to_be32(v); } while (0) -#define ioc3_r_ehar_l() be32_to_cpu(ioc3->ehar_l) -#define ioc3_w_ehar_l(v) do { ioc3->ehar_l = cpu_to_be32(v); } while (0) -#define ioc3_r_micr() be32_to_cpu(ioc3->micr) -#define ioc3_w_micr(v) do { ioc3->micr = cpu_to_be32(v); } while (0) -#define ioc3_r_midr_r() be32_to_cpu(ioc3->midr_r) -#define ioc3_w_midr_r(v) do { ioc3->midr_r = cpu_to_be32(v); } while (0) -#define ioc3_r_midr_w() be32_to_cpu(ioc3->midr_w) -#define ioc3_w_midr_w(v) do { ioc3->midr_w = cpu_to_be32(v); } while (0) - -static inline u32 mcr_pack(u32 pulse, u32 sample) -{ - return (pulse << 10) | (sample << 2); -} - -static int nic_wait(struct ioc3 *ioc3) -{ - u32 mcr; - - do { - mcr = ioc3_r_mcr(); - } while (!(mcr & 2)); - - return mcr & 1; -} - -static int nic_reset(struct ioc3 *ioc3) -{ - int presence; +#define RX_BUF_SIZE 1664 - ioc3_w_mcr(mcr_pack(500, 65)); - presence = nic_wait(ioc3); - - ioc3_w_mcr(mcr_pack(0, 500)); - nic_wait(ioc3); - - return presence; -} - -static inline int nic_read_bit(struct ioc3 *ioc3) +static void ioc3_get_eaddr(struct ioc3_driver_data *idd, struct net_device *dev) { - int result; - - ioc3_w_mcr(mcr_pack(6, 13)); - result = nic_wait(ioc3); - ioc3_w_mcr(mcr_pack(0, 100)); - nic_wait(ioc3); - - return result; -} + int i; -static inline void nic_write_bit(struct ioc3 *ioc3, int bit) -{ - if (bit) - ioc3_w_mcr(mcr_pack(6, 110)); - else - ioc3_w_mcr(mcr_pack(80, 30)); + for (i = 0; i < 6; i++) + dev->dev_addr[i] = idd->nic_mac[i]; - nic_wait(ioc3); + printk(KERN_INFO "ioc3-eth: Ethernet address is %pM.\n", dev->dev_addr); } -/* - * Read a byte from an iButton device - */ -static u32 nic_read_byte(struct ioc3 *ioc3) +static void __ioc3_set_mac_address(struct net_device *dev, struct ioc3 *vma) { - u32 result = 0; - int i; - - for (i = 0; i < 8; i++) - result = (result >> 1) | (nic_read_bit(ioc3) << 7); - - return result; + writel((dev->dev_addr[5] << 8) | + dev->dev_addr[4], + &vma->emar_h); + writel((dev->dev_addr[3] << 24) | + (dev->dev_addr[2] << 16) | + (dev->dev_addr[1] << 8) | + dev->dev_addr[0], + &vma->emar_l); } /* - * Write a byte to an iButton device + * Caller must hold the ioc3_lock ever for MII readers. This is also + * used to protect the transmitter side but it's low contention. */ -static void nic_write_byte(struct ioc3 *ioc3, int byte) +static int ioc3_mdio_read(struct net_device *dev, int phy, int reg) { - int i, bit; + struct ioc3_private *ip = netdev_priv(dev); + struct ioc3 *vma = ip->idd->vma; - for (i = 8; i; i--) { - bit = byte & 1; - byte >>= 1; + while (readl(&vma->micr) & MICR_BUSY); + writel((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG, + &vma->micr); + while (readl(&vma->micr) & MICR_BUSY); - nic_write_bit(ioc3, bit); - } + return readl(&vma->midr_r) & MIDR_DATA_MASK; } -static u64 nic_find(struct ioc3 *ioc3, int *last) +static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data) { - int a, b, index, disc; - u64 address = 0; - - nic_reset(ioc3); - /* Search ROM. */ - nic_write_byte(ioc3, 0xf0); - - /* Algorithm from ``Book of iButton Standards''. */ - for (index = 0, disc = 0; index < 64; index++) { - a = nic_read_bit(ioc3); - b = nic_read_bit(ioc3); - - if (a && b) { - printk("NIC search failed (not fatal).\n"); - *last = 0; - return 0; - } - - if (!a && !b) { - if (index == *last) { - address |= 1UL << index; - } else if (index > *last) { - address &= ~(1UL << index); - disc = index; - } else if ((address & (1UL << index)) == 0) - disc = index; - nic_write_bit(ioc3, address & (1UL << index)); - continue; - } else { - if (a) - address |= 1UL << index; - else - address &= ~(1UL << index); - nic_write_bit(ioc3, a); - continue; - } - } - - *last = disc; + struct ioc3_private *ip = netdev_priv(dev); + struct ioc3 *vma = ip->idd->vma; - return address; + while (readl(&vma->micr) & MICR_BUSY); + writel(data, &vma->midr_w); + writel((phy << MICR_PHYADDR_SHIFT) | reg, &vma->micr); + while (readl(&vma->micr) & MICR_BUSY); } -static int nic_init(struct ioc3 *ioc3) +static void ioc3_stop(struct ioc3_private *ip) { - const char *unknown = "unknown"; - const char *type = unknown; - u8 crc; - u8 serial[6]; - int save = 0, i; - - while (1) { - u64 reg; - reg = nic_find(ioc3, &save); - - switch (reg & 0xff) { - case 0x91: - type = "DS1981U"; - break; - default: - if (save == 0) { - /* Let the caller try again. */ - return -1; - } - continue; - } - - nic_reset(ioc3); - - /* Match ROM. */ - nic_write_byte(ioc3, 0x55); - for (i = 0; i < 8; i++) - nic_write_byte(ioc3, (reg >> (i << 3)) & 0xff); + struct ioc3 *vma = ip->idd->vma; - reg >>= 8; /* Shift out type. */ - for (i = 0; i < 6; i++) { - serial[i] = reg & 0xff; - reg >>= 8; - } - crc = reg & 0xff; - break; - } - - printk("Found %s NIC", type); - if (type != unknown) - printk (" registration number %pM, CRC %02x", serial, crc); - printk(".\n"); - - return 0; + writel(0, &vma->emcr); /* Shutup */ + writel(0, &vma->eier); /* Disable interrupts */ + (void)readl(&vma->eier); /* Flush */ } /* - * Read the NIC (Number-In-a-Can) device used to store the MAC address on - * SN0 / SN00 nodeboards and PCI cards. + * Given a multicast ethernet address, this routine calculates the + * address's bit index in the logical address filter mask */ -static void ioc3_get_eaddr_nic(struct ioc3_private *ip) +static unsigned int ioc3_hash(const unsigned char *addr) { - struct ioc3 *ioc3 = ip->regs; - u8 nic[14]; - int tries = 2; /* There may be some problem with the battery? */ - int i; - - ioc3_w_gpcr_s(1 << 21); + u32 crc; + unsigned int temp = 0; + int bits; - while (tries--) { - if (!nic_init(ioc3)) - break; - udelay(500); - } + crc = ether_crc_le(ETH_ALEN, addr); - if (tries < 0) { - printk("Failed to read MAC address\n"); - return; + crc &= 0x3f; /* bit reverse lowest 6 bits for hash index */ + for (bits = 6; --bits >= 0; ) { + temp <<= 1; + temp |= (crc & 0x1); + crc >>= 1; } - /* Read Memory. */ - nic_write_byte(ioc3, 0xf0); - nic_write_byte(ioc3, 0x00); - nic_write_byte(ioc3, 0x00); - - for (i = 13; i >= 0; i--) - nic[i] = nic_read_byte(ioc3); - - for (i = 2; i < 8; i++) - priv_netdev(ip)->dev_addr[i - 2] = nic[i]; -} - -/* - * Ok, this is hosed by design. It's necessary to know what machine the - * NIC is in in order to know how to read the NIC address. We also have - * to know if it's a PCI card or a NIC in on the node board ... - */ -static void ioc3_get_eaddr(struct ioc3_private *ip) -{ - ioc3_get_eaddr_nic(ip); - - printk("Ethernet address is %pM.\n", priv_netdev(ip)->dev_addr); -} - -static void __ioc3_set_mac_address(struct net_device *dev) -{ - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; - - ioc3_w_emar_h((dev->dev_addr[5] << 8) | dev->dev_addr[4]); - ioc3_w_emar_l((dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | - (dev->dev_addr[1] << 8) | dev->dev_addr[0]); + return temp; } -static int ioc3_set_mac_address(struct net_device *dev, void *addr) +static void ioc3_set_multicast_list(struct net_device *dev) { + struct netdev_hw_addr *ha; struct ioc3_private *ip = netdev_priv(dev); - struct sockaddr *sa = addr; - - memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); + struct ioc3 *vma = ip->idd->vma; + u64 ehar = 0; spin_lock_irq(&ip->ioc3_lock); - __ioc3_set_mac_address(dev); - spin_unlock_irq(&ip->ioc3_lock); - - return 0; -} - -/* - * Caller must hold the ioc3_lock ever for MII readers. This is also - * used to protect the transmitter side but it's low contention. - */ -static int ioc3_mdio_read(struct net_device *dev, int phy, int reg) -{ - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; - - while (ioc3_r_micr() & MICR_BUSY); - ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG); - while (ioc3_r_micr() & MICR_BUSY); - - return ioc3_r_midr_r() & MIDR_DATA_MASK; -} - -static void ioc3_mdio_write(struct net_device *dev, int phy, int reg, int data) -{ - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; - - while (ioc3_r_micr() & MICR_BUSY); - ioc3_w_midr_w(data); - ioc3_w_micr((phy << MICR_PHYADDR_SHIFT) | reg); - while (ioc3_r_micr() & MICR_BUSY); -} - -static int ioc3_mii_init(struct ioc3_private *ip); + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + ip->emcr |= EMCR_PROMISC; + writel(ip->emcr, &vma->emcr); + (void)readl(&vma->emcr); + } else { + ip->emcr &= ~EMCR_PROMISC; + writel(ip->emcr, &vma->emcr); /* Clear promiscuous. */ + (void)readl(&vma->emcr); -static struct net_device_stats *ioc3_get_stats(struct net_device *dev) -{ - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; + if ((dev->flags & IFF_ALLMULTI) || + (netdev_mc_count(dev) > 64)) { + /* Too many for hashing to make sense or we want all + * multicast packets anyway, so skip computing all the + * hashes and just accept all packets. + */ + ip->ehar_h = 0xffffffff; + ip->ehar_l = 0xffffffff; + } else { + netdev_for_each_mc_addr(ha, dev) { + ehar |= (1UL << ioc3_hash(ha->addr)); + } + ip->ehar_h = ehar >> 32; + ip->ehar_l = ehar & 0xffffffff; + } + writel(ip->ehar_h, &vma->ehar_h); + writel(ip->ehar_l, &vma->ehar_l); + } - dev->stats.collisions += (ioc3_r_etcdc() & ETCDC_COLLCNT_MASK); - return &dev->stats; + spin_unlock_irq(&ip->ioc3_lock); } static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) { struct ethhdr *eh = eth_hdr(skb); - uint32_t csum, ehsum; - unsigned int proto; struct iphdr *ih; - uint16_t *ew; unsigned char *cp; + uint16_t *ew; + uint32_t csum, ehsum; + unsigned int proto; /* * Did hardware handle the checksum at all? The cases we can handle @@ -572,288 +319,107 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len) skb->ip_summed = CHECKSUM_UNNECESSARY; } -static inline void ioc3_rx(struct net_device *dev) -{ - struct ioc3_private *ip = netdev_priv(dev); - struct sk_buff *skb, *new_skb; - struct ioc3 *ioc3 = ip->regs; - int rx_entry, n_entry, len; - struct ioc3_erxbuf *rxb; - unsigned long *rxr; - u32 w0, err; +#define ETCSR_FD ((17<rxr; /* Ring base */ - rx_entry = ip->rx_ci; /* RX consume index */ - n_entry = ip->rx_pi; +static void ioc3_setup_duplex(struct ioc3_private *ip) +{ + struct ioc3 *vma = ip->idd->vma; - skb = ip->rx_skbs[rx_entry]; - rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); - w0 = be32_to_cpu(rxb->w0); + if (ip->mii.full_duplex) { + writel(ETCSR_FD, &vma->etcsr); + ip->emcr |= EMCR_DUPLEX; + } else { + writel(ETCSR_HD, &vma->etcsr); + ip->emcr &= ~EMCR_DUPLEX; + } + writel(ip->emcr, &vma->emcr); + (void)readl(&vma->emcr); +} - while (w0 & ERXBUF_V) { - err = be32_to_cpu(rxb->err); /* It's valid ... */ - if (err & ERXBUF_GOODPKT) { - len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4; - skb_trim(skb, len); - skb->protocol = eth_type_trans(skb, dev); +static void ioc3_timer(unsigned long data) +{ + struct ioc3_private *ip = (struct ioc3_private *)data; - new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); - if (!new_skb) { - /* Ouch, drop packet and just recycle packet - to keep the ring filled. */ - dev->stats.rx_dropped++; - new_skb = skb; - goto next; - } + /* Print the link status if it has changed */ + if (mii_check_media(&ip->mii, 1, 0)) + ioc3_setup_duplex(ip); - if (likely(dev->features & NETIF_F_RXCSUM)) - ioc3_tcpudp_checksum(skb, - w0 & ERXBUF_IPCKSUM_MASK, len); + ip->ioc3_timer.expires = jiffies + (2 * HZ); /* 2s */ + add_timer(&ip->ioc3_timer); +} - netif_rx(skb); +/* Try to find a PHY. There is no apparent relation between the MII addresses + * in the SGI documentation and what we find in reality, so we simply probe + * for the PHY. It seems IOC3 PHYs usually live on address 31. One of my + * onboard IOC3s has the special oddity that probing doesn't seem to find it + * yet the interface seems to work fine, so if probing fails we for now will + * simply default to PHY 31 instead of bailing out. + */ +static int ioc3_mii_init(struct ioc3_private *ip) +{ + struct net_device *dev = priv_netdev(ip); + int i, found = 0, res = 0; + int ioc3_phy_workaround = 1; + u16 word; - ip->rx_skbs[rx_entry] = NULL; /* Poison */ + for (i = 0; i < 32; i++) { + word = ioc3_mdio_read(dev, i, MII_PHYSID1); - /* Because we reserve afterwards. */ - skb_put(new_skb, (1664 + RX_OFFSET)); - rxb = (struct ioc3_erxbuf *) new_skb->data; - skb_reserve(new_skb, RX_OFFSET); + if (word != 0xffff && word != 0x0000) { + found = 1; + break; /* Found a PHY */ + } + } - dev->stats.rx_packets++; /* Statistics */ - dev->stats.rx_bytes += len; + if (!found) { + if (ioc3_phy_workaround) { + i = 31; } else { - /* The frame is invalid and the skb never - reached the network layer so we can just - recycle it. */ - new_skb = skb; - dev->stats.rx_errors++; + ip->mii.phy_id = -1; + res = -ENODEV; + goto out; } - if (err & ERXBUF_CRCERR) /* Statistics */ - dev->stats.rx_crc_errors++; - if (err & ERXBUF_FRAMERR) - dev->stats.rx_frame_errors++; -next: - ip->rx_skbs[n_entry] = new_skb; - rxr[n_entry] = cpu_to_be64(ioc3_map(rxb, 1)); - rxb->w0 = 0; /* Clear valid flag */ - n_entry = (n_entry + 1) & 511; /* Update erpir */ - - /* Now go on to the next ring entry. */ - rx_entry = (rx_entry + 1) & 511; - skb = ip->rx_skbs[rx_entry]; - rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); - w0 = be32_to_cpu(rxb->w0); } - ioc3_w_erpir((n_entry << 3) | ERPIR_ARM); - ip->rx_pi = n_entry; - ip->rx_ci = rx_entry; + + ip->mii.phy_id = i; + +out: + return res; } -static inline void ioc3_tx(struct net_device *dev) +static void ioc3_mii_start(struct ioc3_private *ip) { - struct ioc3_private *ip = netdev_priv(dev); - unsigned long packets, bytes; - struct ioc3 *ioc3 = ip->regs; - int tx_entry, o_entry; - struct sk_buff *skb; - u32 etcir; - - spin_lock(&ip->ioc3_lock); - etcir = ioc3_r_etcir(); - - tx_entry = (etcir >> 7) & 127; - o_entry = ip->tx_ci; - packets = 0; - bytes = 0; - - while (o_entry != tx_entry) { - packets++; - skb = ip->tx_skbs[o_entry]; - bytes += skb->len; - dev_kfree_skb_irq(skb); - ip->tx_skbs[o_entry] = NULL; - - o_entry = (o_entry + 1) & 127; /* Next */ - - etcir = ioc3_r_etcir(); /* More pkts sent? */ - tx_entry = (etcir >> 7) & 127; - } - - dev->stats.tx_packets += packets; - dev->stats.tx_bytes += bytes; - ip->txqlen -= packets; - - if (ip->txqlen < 128) - netif_wake_queue(dev); - - ip->tx_ci = o_entry; - spin_unlock(&ip->ioc3_lock); -} - -/* - * Deal with fatal IOC3 errors. This condition might be caused by a hard or - * software problems, so we should try to recover - * more gracefully if this ever happens. In theory we might be flooded - * with such error interrupts if something really goes wrong, so we might - * also consider to take the interface down. - */ -static void ioc3_error(struct net_device *dev, u32 eisr) -{ - struct ioc3_private *ip = netdev_priv(dev); - unsigned char *iface = dev->name; - - spin_lock(&ip->ioc3_lock); - - if (eisr & EISR_RXOFLO) - printk(KERN_ERR "%s: RX overflow.\n", iface); - if (eisr & EISR_RXBUFOFLO) - printk(KERN_ERR "%s: RX buffer overflow.\n", iface); - if (eisr & EISR_RXMEMERR) - printk(KERN_ERR "%s: RX PCI error.\n", iface); - if (eisr & EISR_RXPARERR) - printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface); - if (eisr & EISR_TXBUFUFLO) - printk(KERN_ERR "%s: TX buffer underflow.\n", iface); - if (eisr & EISR_TXMEMERR) - printk(KERN_ERR "%s: TX PCI error.\n", iface); - - ioc3_stop(ip); - ioc3_init(dev); - ioc3_mii_init(ip); - - netif_wake_queue(dev); - - spin_unlock(&ip->ioc3_lock); -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static irqreturn_t ioc3_interrupt(int irq, void *_dev) -{ - struct net_device *dev = (struct net_device *)_dev; - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; - const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO | - EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO | - EISR_TXEXPLICIT | EISR_TXMEMERR; - u32 eisr; - - eisr = ioc3_r_eisr() & enabled; - - ioc3_w_eisr(eisr); - (void) ioc3_r_eisr(); /* Flush */ - - if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR | - EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR)) - ioc3_error(dev, eisr); - if (eisr & EISR_RXTIMERINT) - ioc3_rx(dev); - if (eisr & EISR_TXEXPLICIT) - ioc3_tx(dev); - - return IRQ_HANDLED; -} - -static inline void ioc3_setup_duplex(struct ioc3_private *ip) -{ - struct ioc3 *ioc3 = ip->regs; - - if (ip->mii.full_duplex) { - ioc3_w_etcsr(ETCSR_FD); - ip->emcr |= EMCR_DUPLEX; - } else { - ioc3_w_etcsr(ETCSR_HD); - ip->emcr &= ~EMCR_DUPLEX; - } - ioc3_w_emcr(ip->emcr); -} - -static void ioc3_timer(unsigned long data) -{ - struct ioc3_private *ip = (struct ioc3_private *) data; - - /* Print the link status if it has changed */ - mii_check_media(&ip->mii, 1, 0); - ioc3_setup_duplex(ip); - - ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */ - add_timer(&ip->ioc3_timer); -} - -/* - * Try to find a PHY. There is no apparent relation between the MII addresses - * in the SGI documentation and what we find in reality, so we simply probe - * for the PHY. It seems IOC3 PHYs usually live on address 31. One of my - * onboard IOC3s has the special oddity that probing doesn't seem to find it - * yet the interface seems to work fine, so if probing fails we for now will - * simply default to PHY 31 instead of bailing out. - */ -static int ioc3_mii_init(struct ioc3_private *ip) -{ - struct net_device *dev = priv_netdev(ip); - int i, found = 0, res = 0; - int ioc3_phy_workaround = 1; - u16 word; - - for (i = 0; i < 32; i++) { - word = ioc3_mdio_read(dev, i, MII_PHYSID1); - - if (word != 0xffff && word != 0x0000) { - found = 1; - break; /* Found a PHY */ - } - } - - if (!found) { - if (ioc3_phy_workaround) - i = 31; - else { - ip->mii.phy_id = -1; - res = -ENODEV; - goto out; - } - } - - ip->mii.phy_id = i; - -out: - return res; -} - -static void ioc3_mii_start(struct ioc3_private *ip) -{ - ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ + ip->ioc3_timer.expires = jiffies + (2 * HZ); /* 2 sec. */ ip->ioc3_timer.data = (unsigned long) ip; ip->ioc3_timer.function = ioc3_timer; + add_timer(&ip->ioc3_timer); } -static inline void ioc3_clean_rx_ring(struct ioc3_private *ip) +static void ioc3_clean_rx_ring(struct ioc3_private *ip) { struct sk_buff *skb; + struct ioc3_erxbuf *rxb; int i; - for (i = ip->rx_ci; i & 15; i++) { - ip->rx_skbs[ip->rx_pi] = ip->rx_skbs[ip->rx_ci]; - ip->rxr[ip->rx_pi++] = ip->rxr[ip->rx_ci++]; - } - ip->rx_pi &= 511; - ip->rx_ci &= 511; - - for (i = ip->rx_ci; i != ip->rx_pi; i = (i+1) & 511) { - struct ioc3_erxbuf *rxb; + for (i = 0; i < RX_BUFFS; i++) { skb = ip->rx_skbs[i]; - rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); - rxb->w0 = 0; + if (skb) { + rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); + rxb->w0 = 0; + } } + ip->rx_ci = 0; + ip->rx_pi = RX_BUFFS - 16; } -static inline void ioc3_clean_tx_ring(struct ioc3_private *ip) +static void ioc3_clean_tx_ring(struct ioc3_private *ip) { struct sk_buff *skb; int i; - for (i=0; i < 128; i++) { + for (i = 0; i < TX_BUFFS; i++) { skb = ip->tx_skbs[i]; if (skb) { ip->tx_skbs[i] = NULL; @@ -868,7 +434,7 @@ static inline void ioc3_clean_tx_ring(struct ioc3_private *ip) static void ioc3_free_rings(struct ioc3_private *ip) { struct sk_buff *skb; - int rx_entry, n_entry; + int i; if (ip->txr) { ioc3_clean_tx_ring(ip); @@ -877,15 +443,10 @@ static void ioc3_free_rings(struct ioc3_private *ip) } if (ip->rxr) { - n_entry = ip->rx_ci; - rx_entry = ip->rx_pi; - - while (n_entry != rx_entry) { - skb = ip->rx_skbs[n_entry]; + for (i = 0; i < RX_BUFFS; i++) { + skb = ip->rx_skbs[i]; if (skb) dev_kfree_skb_any(skb); - - n_entry = (n_entry + 1) & 511; } free_page((unsigned long)ip->rxr); ip->rxr = NULL; @@ -904,15 +465,15 @@ static void ioc3_alloc_rings(struct net_device *dev) ip->rxr = (unsigned long *) get_zeroed_page(GFP_ATOMIC); rxr = ip->rxr; if (!rxr) - printk("ioc3_alloc_rings(): get_zeroed_page() failed!\n"); + printk(KERN_ERR "ioc3_alloc_rings(): get_zeroed_page() failed!\n"); /* Now the rx buffers. The RX ring may be larger but - we only allocate 16 buffers for now. Need to tune + we only allocate RX_BUFFS buffers for now. Need to tune this for performance and memory later. */ for (i = 0; i < RX_BUFFS; i++) { struct sk_buff *skb; - skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + skb = ioc3_alloc_skb(dev); if (!skb) { show_free_areas(0); continue; @@ -921,141 +482,134 @@ static void ioc3_alloc_rings(struct net_device *dev) ip->rx_skbs[i] = skb; /* Because we reserve afterwards. */ - skb_put(skb, (1664 + RX_OFFSET)); + skb_put(skb, 1664); rxb = (struct ioc3_erxbuf *) skb->data; - rxr[i] = cpu_to_be64(ioc3_map(rxb, 1)); + rxr[i] = cpu_to_be64(ioc3_map(rxb, PCI64_ATTR_BAR)); skb_reserve(skb, RX_OFFSET); } - ip->rx_ci = 0; - ip->rx_pi = RX_BUFFS; } if (ip->txr == NULL) { /* Allocate and initialize tx rings. 16kb = 128 bufs. */ - ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2); + ip->txr = (struct ioc3_etxd *)__get_free_pages((GFP_ATOMIC | __GFP_ZERO), 2); if (!ip->txr) - printk("ioc3_alloc_rings(): __get_free_pages() failed!\n"); - ip->tx_pi = 0; - ip->tx_ci = 0; + printk(KERN_ERR "ioc3_alloc_rings(): __get_free_pages() failed!\n"); } } static void ioc3_init_rings(struct net_device *dev) { struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; + struct ioc3 *vma = ip->idd->vma; unsigned long ring; ioc3_free_rings(ip); ioc3_alloc_rings(dev); - ioc3_clean_rx_ring(ip); ioc3_clean_tx_ring(ip); /* Now the rx ring base, consume & produce registers. */ - ring = ioc3_map(ip->rxr, 0); - ioc3_w_erbr_h(ring >> 32); - ioc3_w_erbr_l(ring & 0xffffffff); - ioc3_w_ercir(ip->rx_ci << 3); - ioc3_w_erpir((ip->rx_pi << 3) | ERPIR_ARM); - - ring = ioc3_map(ip->txr, 0); - - ip->txqlen = 0; /* nothing queued */ + ring = ioc3_map(ip->rxr, PCI64_ATTR_VIRTUAL | PCI64_ATTR_PREC); + writel(ring >> 32, &vma->erbr_h); + writel(ring & 0xffffffff, &vma->erbr_l); + writel(ip->rx_ci << 3, &vma->ercir); + writel((ip->rx_pi << 3) | ERPIR_ARM, &vma->erpir); /* Now the tx ring base, consume & produce registers. */ - ioc3_w_etbr_h(ring >> 32); - ioc3_w_etbr_l(ring & 0xffffffff); - ioc3_w_etpir(ip->tx_pi << 7); - ioc3_w_etcir(ip->tx_ci << 7); - (void) ioc3_r_etcir(); /* Flush */ + ring = ioc3_map(ip->txr, PCI64_ATTR_VIRTUAL | PCI64_ATTR_PREC); + ip->txbfree = TX_BUFFS; /* nothing queued */ + writel(ring >> 32, &vma->etbr_h); + writel(ring & 0xffffffff, &vma->etbr_l); + writel(ip->tx_pi << 7, &vma->etpir); + writel(ip->tx_ci << 7, &vma->etcir); + (void)readl(&vma->etcir); /* Flush */ } -static inline void ioc3_ssram_disc(struct ioc3_private *ip) +static void ioc3_ssram_disc(struct ioc3_private *ip) { - struct ioc3 *ioc3 = ip->regs; - volatile u32 *ssram0 = &ioc3->ssram[0x0000]; - volatile u32 *ssram1 = &ioc3->ssram[0x4000]; - unsigned int pattern = 0x5555; + struct ioc3 *vma = ip->idd->vma; + u32 *emcr_p = &vma->emcr; + u32 *ssram0 = &vma->ssram[0x0000]; + u32 *ssram1 = &vma->ssram[0x4000]; + const unsigned int pattern0 = 0x5555; + const unsigned int pattern1 = ~pattern0 & IOC3_SSRAM_DM; /* Assume the larger size SSRAM and enable parity checking */ - ioc3_w_emcr(ioc3_r_emcr() | (EMCR_BUFSIZ | EMCR_RAMPAR)); + writel(readl(emcr_p) | EMCR_BUFSIZ | EMCR_RAMPAR, emcr_p); + (void)readl(emcr_p); - *ssram0 = pattern; - *ssram1 = ~pattern & IOC3_SSRAM_DM; + writel(pattern0, ssram0); + writel(pattern1, ssram1); - if ((*ssram0 & IOC3_SSRAM_DM) != pattern || - (*ssram1 & IOC3_SSRAM_DM) != (~pattern & IOC3_SSRAM_DM)) { + if (((readl(ssram0) & IOC3_SSRAM_DM) != pattern0) || + ((readl(ssram1) & IOC3_SSRAM_DM) != pattern1)) { /* set ssram size to 64 KB */ - ip->emcr = EMCR_RAMPAR; - ioc3_w_emcr(ioc3_r_emcr() & ~EMCR_BUFSIZ); - } else - ip->emcr = EMCR_BUFSIZ | EMCR_RAMPAR; + ip->emcr |= EMCR_RAMPAR; + writel(readl(emcr_p) & ~EMCR_BUFSIZ, emcr_p); + (void)readl(emcr_p); + } else { + ip->emcr |= EMCR_RAMPAR | EMCR_BUFSIZ; + } } static void ioc3_init(struct net_device *dev) { struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; + struct ioc3 *vma = ip->idd->vma; del_timer_sync(&ip->ioc3_timer); /* Kill if running */ - ioc3_w_emcr(EMCR_RST); /* Reset */ - (void) ioc3_r_emcr(); /* Flush WB */ + writel(EMCR_RST, &vma->emcr); /* Reset */ + (void)readl(&vma->emcr); /* Flush WB */ udelay(4); /* Give it time ... */ - ioc3_w_emcr(0); - (void) ioc3_r_emcr(); + writel(0, &vma->emcr); + (void)readl(&vma->emcr); /* Misc registers */ #ifdef CONFIG_SGI_IP27 - ioc3_w_erbar(PCI64_ATTR_BAR >> 32); /* Barrier on last store */ + /* Barrier on last store */ + writel(readl(&vma->erbar) | + (ERBAR_BARRIER_BIT << ERBAR_RXBARR_SHIFT), &vma->erbar); #else - ioc3_w_erbar(0); /* Let PCI API get it right */ + /* Let PCI API get it right */ + writel(0, &vma->erbar); #endif - (void) ioc3_r_etcdc(); /* Clear on read */ - ioc3_w_ercsr(15); /* RX low watermark */ - ioc3_w_ertr(0); /* Interrupt immediately */ - __ioc3_set_mac_address(dev); - ioc3_w_ehar_h(ip->ehar_h); - ioc3_w_ehar_l(ip->ehar_l); - ioc3_w_ersr(42); /* XXX should be random */ + (void)readl(&vma->etcdc); /* Clear on read */ + writel(15, &vma->ercsr); /* RX low watermark */ + writel(1, &vma->ertr); /* Interrupt immediately */ + __ioc3_set_mac_address(dev, vma); + writel(ip->ehar_h, &vma->ehar_h); + writel(ip->ehar_l, &vma->ehar_l); + writel(42, &vma->ersr); /* XXX Should be random */ ioc3_init_rings(dev); - ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN | - EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN | EMCR_PADEN; - ioc3_w_emcr(ip->emcr); - ioc3_w_eier(EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO | - EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO | - EISR_TXEXPLICIT | EISR_TXMEMERR); - (void) ioc3_r_eier(); -} - -static inline void ioc3_stop(struct ioc3_private *ip) -{ - struct ioc3 *ioc3 = ip->regs; - - ioc3_w_emcr(0); /* Shutup */ - ioc3_w_eier(0); /* Disable interrupts */ - (void) ioc3_r_eier(); /* Flush */ + ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | + EMCR_TXDMAEN | EMCR_TXEN | + EMCR_RXDMAEN | EMCR_RXEN | + EMCR_PADEN; + writel(ip->emcr, &vma->emcr); + (void)readl(&vma->emcr); + writel(EISR_RXTIMERINT | EISR_RXTHRESHINT | + EISR_RXOFLO | EISR_RXBUFOFLO | + EISR_RXMEMERR | EISR_RXPARERR | + EISR_TXEXDEF | + EISR_TXBUFUFLO | + EISR_TXMEMERR, &vma->eier); + (void)readl(&vma->eier); } static int ioc3_open(struct net_device *dev) { struct ioc3_private *ip = netdev_priv(dev); - if (request_irq(dev->irq, ioc3_interrupt, IRQF_SHARED, ioc3_str, dev)) { - printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq); - - return -EAGAIN; - } - ip->ehar_h = 0; ip->ehar_l = 0; ioc3_init(dev); + ioc3_mii_init(ip); ioc3_mii_start(ip); - netif_start_queue(dev); + return 0; } @@ -1064,400 +618,82 @@ static int ioc3_close(struct net_device *dev) struct ioc3_private *ip = netdev_priv(dev); del_timer_sync(&ip->ioc3_timer); - netif_stop_queue(dev); - ioc3_stop(ip); - free_irq(dev->irq, dev); - ioc3_free_rings(ip); + return 0; } -/* - * MENET cards have four IOC3 chips, which are attached to two sets of - * PCI slot resources each: the primary connections are on slots - * 0..3 and the secondaries are on 4..7 - * - * All four ethernets are brought out to connectors; six serial ports - * (a pair from each of the first three IOC3s) are brought out to - * MiniDINs; all other subdevices are left swinging in the wind, leave - * them disabled. - */ - -static int ioc3_adjacent_is_ioc3(struct pci_dev *pdev, int slot) +static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pci_dev *dev = pci_get_slot(pdev->bus, PCI_DEVFN(slot, 0)); - int ret = 0; - - if (dev) { - if (dev->vendor == PCI_VENDOR_ID_SGI && - dev->device == PCI_DEVICE_ID_SGI_IOC3) - ret = 1; - pci_dev_put(dev); - } - - return ret; -} + struct ioc3_private *ip = netdev_priv(dev); + struct ioc3_etxd *desc; + unsigned long data; + unsigned int len; + uint32_t w0 = 0; + int produce; -static int ioc3_is_menet(struct pci_dev *pdev) -{ - return pdev->bus->parent == NULL && - ioc3_adjacent_is_ioc3(pdev, 0) && - ioc3_adjacent_is_ioc3(pdev, 1) && - ioc3_adjacent_is_ioc3(pdev, 2); -} + /* IOC3 has a fairly simple minded checksumming hardware which simply + * adds up the 1's complement checksum for the entire packet and + * inserts it at an offset which can be specified in the descriptor + * into the transmit packet. This means we have to compensate for the + * MAC header which should not be summed and the TCP/UDP pseudo headers + * manually. + */ + if (skb->ip_summed == CHECKSUM_PARTIAL) { + struct iphdr *ih = ip_hdr(skb); + int proto = ntohs(ih->protocol); + unsigned int csoff; + uint32_t csum, ehsum; + uint16_t *eh; -#ifdef CONFIG_SERIAL_8250 -/* - * Note about serial ports and consoles: - * For console output, everyone uses the IOC3 UARTA (offset 0x178) - * connected to the master node (look in ip27_setup_console() and - * ip27prom_console_write()). - * - * For serial (/dev/ttyS0 etc), we can not have hardcoded serial port - * addresses on a partitioned machine. Since we currently use the ioc3 - * serial ports, we use dynamic serial port discovery that the serial.c - * driver uses for pci/pnp ports (there is an entry for the SGI ioc3 - * boards in pci_boards[]). Unfortunately, UARTA's pio address is greater - * than UARTB's, although UARTA on o200s has traditionally been known as - * port 0. So, we just use one serial port from each ioc3 (since the - * serial driver adds addresses to get to higher ports). - * - * The first one to do a register_console becomes the preferred console - * (if there is no kernel command line console= directive). /dev/console - * (ie 5, 1) is then "aliased" into the device number returned by the - * "device" routine referred to in this console structure - * (ip27prom_console_dev). - * - * Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working - * around ioc3 oddities in this respect. - * - * The IOC3 serials use a 22MHz clock rate with an additional divider which - * can be programmed in the SCR register if the DLAB bit is set. - * - * Register to interrupt zero because we share the interrupt with - * the serial driver which we don't properly support yet. - * - * Can't use UPF_IOREMAP as the whole of IOC3 resources have already been - * registered. - */ -static void ioc3_8250_register(struct ioc3_uartregs __iomem *uart) -{ -#define COSMISC_CONSTANT 6 - - struct uart_8250_port port = { - .port = { - .irq = 0, - .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, - .iotype = UPIO_MEM, - .regshift = 0, - .uartclk = (22000000 << 1) / COSMISC_CONSTANT, - - .membase = (unsigned char __iomem *) uart, - .mapbase = (unsigned long) uart, - } - }; - unsigned char lcr; - - lcr = uart->iu_lcr; - uart->iu_lcr = lcr | UART_LCR_DLAB; - uart->iu_scr = COSMISC_CONSTANT, - uart->iu_lcr = lcr; - uart->iu_lcr; - serial8250_register_8250_port(&port); -} + /* The MAC header. skb->mac seem the logic approach + * to find the MAC header - except it's a NULL pointer ... + */ + eh = (uint16_t *)skb->data; -static void ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) -{ - /* - * We need to recognice and treat the fourth MENET serial as it - * does not have an SuperIO chip attached to it, therefore attempting - * to access it will result in bus errors. We call something an - * MENET if PCI slot 0, 1, 2 and 3 of a master PCI bus all have an IOC3 - * in it. This is paranoid but we want to avoid blowing up on a - * showhorn PCI box that happens to have 4 IOC3 cards in it so it's - * not paranoid enough ... - */ - if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3) - return; + /* Sum up dest addr, src addr and protocol */ + ehsum = eh[0] + eh[1] + eh[2] + eh[3] + eh[4] + eh[5] + eh[6]; - /* - * Switch IOC3 to PIO mode. It probably already was but let's be - * paranoid - */ - ioc3->gpcr_s = GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL; - ioc3->gpcr_s; - ioc3->gppr_6 = 0; - ioc3->gppr_6; - ioc3->gppr_7 = 0; - ioc3->gppr_7; - ioc3->sscr_a = ioc3->sscr_a & ~SSCR_DMA_EN; - ioc3->sscr_a; - ioc3->sscr_b = ioc3->sscr_b & ~SSCR_DMA_EN; - ioc3->sscr_b; - /* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */ - ioc3->sio_iec &= ~ (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_TX_EXPLICIT | SIO_IR_SA_MEMERR); - ioc3->sio_iec |= SIO_IR_SA_INT; - ioc3->sscr_a = 0; - ioc3->sio_iec &= ~ (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_TX_EXPLICIT | SIO_IR_SB_MEMERR); - ioc3->sio_iec |= SIO_IR_SB_INT; - ioc3->sscr_b = 0; - - ioc3_8250_register(&ioc3->sregs.uarta); - ioc3_8250_register(&ioc3->sregs.uartb); -} -#endif + /* Skip IP header; it's sum is always zero and was + * already filled in by ip_output.c + */ + csum = csum_tcpudp_nofold(ih->saddr, ih->daddr, + ih->tot_len - (ih->ihl << 2), + proto, csum_fold(ehsum)); -static const struct net_device_ops ioc3_netdev_ops = { - .ndo_open = ioc3_open, - .ndo_stop = ioc3_close, - .ndo_start_xmit = ioc3_start_xmit, - .ndo_tx_timeout = ioc3_timeout, - .ndo_get_stats = ioc3_get_stats, - .ndo_set_rx_mode = ioc3_set_multicast_list, - .ndo_do_ioctl = ioc3_ioctl, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = ioc3_set_mac_address, - .ndo_change_mtu = eth_change_mtu, -}; + csum = (csum & 0xffff) + (csum >> 16); /* Fold again */ + csum = (csum & 0xffff) + (csum >> 16); -static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - unsigned int sw_physid1, sw_physid2; - struct net_device *dev = NULL; - struct ioc3_private *ip; - struct ioc3 *ioc3; - unsigned long ioc3_base, ioc3_size; - u32 vendor, model, rev; - int err, pci_using_dac; - - /* Configure DMA attributes. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (!err) { - pci_using_dac = 1; - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err < 0) { - printk(KERN_ERR "%s: Unable to obtain 64 bit DMA " - "for consistent allocations\n", pci_name(pdev)); - goto out; + csoff = ETH_HLEN + (ih->ihl << 2); + if (proto == IPPROTO_UDP) { + csoff += offsetof(struct udphdr, check); + udp_hdr(skb)->check = csum; } - } else { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - printk(KERN_ERR "%s: No usable DMA configuration, " - "aborting.\n", pci_name(pdev)); - goto out; + if (proto == IPPROTO_TCP) { + csoff += offsetof(struct tcphdr, check); + tcp_hdr(skb)->check = csum; } - pci_using_dac = 0; - } - if (pci_enable_device(pdev)) - return -ENODEV; - - dev = alloc_etherdev(sizeof(struct ioc3_private)); - if (!dev) { - err = -ENOMEM; - goto out_disable; + w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); } - if (pci_using_dac) - dev->features |= NETIF_F_HIGHDMA; - - err = pci_request_regions(pdev, "ioc3"); - if (err) - goto out_free; - - SET_NETDEV_DEV(dev, &pdev->dev); - - ip = netdev_priv(dev); - - dev->irq = pdev->irq; + spin_lock_irq(&ip->ioc3_lock); - ioc3_base = pci_resource_start(pdev, 0); - ioc3_size = pci_resource_len(pdev, 0); - ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size); - if (!ioc3) { - printk(KERN_CRIT "ioc3eth(%s): ioremap failed, goodbye.\n", - pci_name(pdev)); - err = -ENOMEM; - goto out_res; + if ((ip->txbfree <= 0)) { + netif_stop_queue(dev); + spin_unlock_irq(&ip->ioc3_lock); + printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); + return NETDEV_TX_BUSY; } - ip->regs = ioc3; - -#ifdef CONFIG_SERIAL_8250 - ioc3_serial_probe(pdev, ioc3); -#endif - spin_lock_init(&ip->ioc3_lock); - init_timer(&ip->ioc3_timer); - - ioc3_stop(ip); - ioc3_init(dev); + data = (unsigned long)skb->data; + len = skb->len; - ip->pdev = pdev; - - ip->mii.phy_id_mask = 0x1f; - ip->mii.reg_num_mask = 0x1f; - ip->mii.dev = dev; - ip->mii.mdio_read = ioc3_mdio_read; - ip->mii.mdio_write = ioc3_mdio_write; - - ioc3_mii_init(ip); - - if (ip->mii.phy_id == -1) { - printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n", - pci_name(pdev)); - err = -ENODEV; - goto out_stop; - } - - ioc3_mii_start(ip); - ioc3_ssram_disc(ip); - ioc3_get_eaddr(ip); - - /* The IOC3-specific entries in the device structure. */ - dev->watchdog_timeo = 5 * HZ; - dev->netdev_ops = &ioc3_netdev_ops; - dev->ethtool_ops = &ioc3_ethtool_ops; - dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - dev->features = NETIF_F_IP_CSUM; - - sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); - sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); - - err = register_netdev(dev); - if (err) - goto out_stop; - - mii_check_media(&ip->mii, 1, 1); - ioc3_setup_duplex(ip); - - vendor = (sw_physid1 << 12) | (sw_physid2 >> 4); - model = (sw_physid2 >> 4) & 0x3f; - rev = sw_physid2 & 0xf; - printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, " - "rev %d.\n", dev->name, ip->mii.phy_id, vendor, model, rev); - printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name, - ip->emcr & EMCR_BUFSIZ ? 128 : 64); - - return 0; - -out_stop: - ioc3_stop(ip); - del_timer_sync(&ip->ioc3_timer); - ioc3_free_rings(ip); -out_res: - pci_release_regions(pdev); -out_free: - free_netdev(dev); -out_disable: - /* - * We should call pci_disable_device(pdev); here if the IOC3 wasn't - * such a weird device ... - */ -out: - return err; -} - -static void ioc3_remove_one(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; - - unregister_netdev(dev); - del_timer_sync(&ip->ioc3_timer); - - iounmap(ioc3); - pci_release_regions(pdev); - free_netdev(dev); - /* - * We should call pci_disable_device(pdev); here if the IOC3 wasn't - * such a weird device ... - */ -} - -static const struct pci_device_id ioc3_pci_tbl[] = { - { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, ioc3_pci_tbl); - -static struct pci_driver ioc3_driver = { - .name = "ioc3-eth", - .id_table = ioc3_pci_tbl, - .probe = ioc3_probe, - .remove = ioc3_remove_one, -}; - -static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - unsigned long data; - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; - unsigned int len; - struct ioc3_etxd *desc; - uint32_t w0 = 0; - int produce; - - /* - * IOC3 has a fairly simple minded checksumming hardware which simply - * adds up the 1's complement checksum for the entire packet and - * inserts it at an offset which can be specified in the descriptor - * into the transmit packet. This means we have to compensate for the - * MAC header which should not be summed and the TCP/UDP pseudo headers - * manually. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - const struct iphdr *ih = ip_hdr(skb); - const int proto = ntohs(ih->protocol); - unsigned int csoff; - uint32_t csum, ehsum; - uint16_t *eh; - - /* The MAC header. skb->mac seem the logic approach - to find the MAC header - except it's a NULL pointer ... */ - eh = (uint16_t *) skb->data; - - /* Sum up dest addr, src addr and protocol */ - ehsum = eh[0] + eh[1] + eh[2] + eh[3] + eh[4] + eh[5] + eh[6]; - - /* Skip IP header; it's sum is always zero and was - already filled in by ip_output.c */ - csum = csum_tcpudp_nofold(ih->saddr, ih->daddr, - ih->tot_len - (ih->ihl << 2), - proto, csum_fold(ehsum)); - - csum = (csum & 0xffff) + (csum >> 16); /* Fold again */ - csum = (csum & 0xffff) + (csum >> 16); - - csoff = ETH_HLEN + (ih->ihl << 2); - if (proto == IPPROTO_UDP) { - csoff += offsetof(struct udphdr, check); - udp_hdr(skb)->check = csum; - } - if (proto == IPPROTO_TCP) { - csoff += offsetof(struct tcphdr, check); - tcp_hdr(skb)->check = csum; - } - - w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT); - } - - spin_lock_irq(&ip->ioc3_lock); - - data = (unsigned long) skb->data; - len = skb->len; - - produce = ip->tx_pi; - desc = &ip->txr[produce]; + produce = ip->tx_pi; + desc = &ip->txr[produce]; if (len <= 104) { /* Short packet, let's copy it directly into the ring. */ @@ -1478,25 +714,27 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) ETXD_B1V | ETXD_B2V | w0); desc->bufcnt = cpu_to_be32((s1 << ETXD_B1CNT_SHIFT) | (s2 << ETXD_B2CNT_SHIFT)); - desc->p1 = cpu_to_be64(ioc3_map(skb->data, 1)); - desc->p2 = cpu_to_be64(ioc3_map((void *) b2, 1)); + desc->p1 = cpu_to_be64(ioc3_map(skb->data, + PCI64_ATTR_PREF)); + desc->p2 = cpu_to_be64(ioc3_map((void *)b2, + PCI64_ATTR_PREF)); } else { /* Normal sized packet that doesn't cross a page boundary. */ desc->cmd = cpu_to_be32(len | ETXD_INTWHENDONE | ETXD_B1V | w0); desc->bufcnt = cpu_to_be32(len << ETXD_B1CNT_SHIFT); - desc->p1 = cpu_to_be64(ioc3_map(skb->data, 1)); + desc->p1 = cpu_to_be64(ioc3_map(skb->data, + PCI64_ATTR_PREF)); } BARRIER(); - ip->tx_skbs[produce] = skb; /* Remember skb */ - produce = (produce + 1) & 127; + ip->tx_skbs[produce] = skb; /* Remember skb */ + produce = (produce + 1) & TX_MASK; ip->tx_pi = produce; - ioc3_w_etpir(produce << 7); /* Fire ... */ + writel(produce << 7, &ip->idd->vma->etpir); /* Fire ... */ - ip->txqlen++; - - if (ip->txqlen >= 127) + ip->txbfree--; + if (ip->txbfree == 0) netif_stop_queue(dev); spin_unlock_irq(&ip->ioc3_lock); @@ -1504,55 +742,78 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static void ioc3_timeout(struct net_device *dev) +static int ioc3_set_mac_address(struct net_device *dev, void *addr) { struct ioc3_private *ip = netdev_priv(dev); + struct ioc3 *vma = ip->idd->vma; + struct sockaddr *sa = addr; - printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); spin_lock_irq(&ip->ioc3_lock); + __ioc3_set_mac_address(dev, vma); + spin_unlock_irq(&ip->ioc3_lock); + + return 0; +} + +static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct ioc3_private *ip = netdev_priv(dev); + int rc; + + spin_lock_irq(&ip->ioc3_lock); + rc = generic_mii_ioctl(&ip->mii, if_mii(rq), cmd, NULL); + spin_unlock_irq(&ip->ioc3_lock); + + return rc; +} + +static void ioc3_timeout(struct net_device *dev) +{ + struct ioc3_private *ip = netdev_priv(dev); + + printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); ioc3_stop(ip); ioc3_init(dev); ioc3_mii_init(ip); ioc3_mii_start(ip); - spin_unlock_irq(&ip->ioc3_lock); - netif_wake_queue(dev); } -/* - * Given a multicast ethernet address, this routine calculates the - * address's bit index in the logical address filter mask - */ - -static inline unsigned int ioc3_hash(const unsigned char *addr) +static struct net_device_stats *ioc3_get_stats(struct net_device *dev) { - unsigned int temp = 0; - u32 crc; - int bits; - - crc = ether_crc_le(ETH_ALEN, addr); - - crc &= 0x3f; /* bit reverse lowest 6 bits for hash index */ - for (bits = 6; --bits >= 0; ) { - temp <<= 1; - temp |= (crc & 0x1); - crc >>= 1; - } + struct ioc3_private *ip = netdev_priv(dev); + struct ioc3 *vma = ip->idd->vma; - return temp; + dev->stats.collisions += (readl(&vma->etcdc) & ETCDC_COLLCNT_MASK); + return &dev->stats; } +static const struct net_device_ops ioc3_netdev_ops = { + .ndo_open = ioc3_open, + .ndo_stop = ioc3_close, + .ndo_start_xmit = ioc3_start_xmit, + .ndo_tx_timeout = ioc3_timeout, + .ndo_set_rx_mode = ioc3_set_multicast_list, + .ndo_set_mac_address = ioc3_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = ioc3_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_get_stats = ioc3_get_stats, +}; + static void ioc3_get_drvinfo (struct net_device *dev, - struct ethtool_drvinfo *info) + struct ethtool_drvinfo *info) { struct ioc3_private *ip = netdev_priv(dev); strlcpy(info->driver, IOC3_NAME, sizeof(info->driver)); strlcpy(info->version, IOC3_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, pci_name(ip->pdev), sizeof(info->bus_info)); + strlcpy(info->bus_info, pci_name(ip->idd->pdev), + sizeof(info->bus_info)); } static int ioc3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -1611,58 +872,301 @@ static const struct ethtool_ops ioc3_ethtool_ops = { .get_link = ioc3_get_link, }; -static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +/* Deal with fatal IOC3 errors. This condition might be caused by a hard or + * software problems, so we should try to recover + * more gracefully if this ever happens. In theory we might be flooded + * with such error interrupts if something really goes wrong, so we might + * also consider to take the interface down. + */ +static noinline void ioc3_error(struct ioc3_private *ip, + struct net_device *dev, u32 eisr) { - struct ioc3_private *ip = netdev_priv(dev); - int rc; + unsigned char *iface = dev->name; - spin_lock_irq(&ip->ioc3_lock); - rc = generic_mii_ioctl(&ip->mii, if_mii(rq), cmd, NULL); - spin_unlock_irq(&ip->ioc3_lock); + if (eisr & EISR_RXOFLO) + printk(KERN_ERR "%s: RX overflow.\n", iface); + if (eisr & EISR_RXBUFOFLO) + printk(KERN_ERR "%s: RX buffer overflow.\n", iface); + if (eisr & EISR_RXMEMERR) + printk(KERN_ERR "%s: RX PCI error.\n", iface); + if (eisr & EISR_RXPARERR) + printk(KERN_ERR "%s: RX SSRAM parity error.\n", iface); + if (eisr & EISR_TXBUFUFLO) + printk(KERN_ERR "%s: TX buffer underflow.\n", iface); + if (eisr & EISR_TXMEMERR) + printk(KERN_ERR "%s: TX PCI error.\n", iface); - return rc; + ioc3_stop(ip); + + /* This can trigger a BUG(): sleeping function called */ + ioc3_init(dev); + ioc3_mii_init(ip); + ioc3_mii_start(ip); + + netif_wake_queue(dev); } -static void ioc3_set_multicast_list(struct net_device *dev) +static noinline void ioc3_rx(struct ioc3_private *ip, struct net_device *dev) { - struct netdev_hw_addr *ha; - struct ioc3_private *ip = netdev_priv(dev); - struct ioc3 *ioc3 = ip->regs; - u64 ehar = 0; + struct sk_buff *skb, *new_skb; + struct ioc3_erxbuf *rxb; + int rx_entry, n_entry, len; + u32 w0, err; + + rx_entry = ip->rx_ci; /* RX consume index */ + n_entry = ip->rx_pi; - netif_stop_queue(dev); /* Lock out others. */ + skb = ip->rx_skbs[rx_entry]; + rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); + w0 = be32_to_cpu(rxb->w0); - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - ip->emcr |= EMCR_PROMISC; - ioc3_w_emcr(ip->emcr); - (void) ioc3_r_emcr(); - } else { - ip->emcr &= ~EMCR_PROMISC; - ioc3_w_emcr(ip->emcr); /* Clear promiscuous. */ - (void) ioc3_r_emcr(); + while (w0 & ERXBUF_V) { + err = be32_to_cpu(rxb->err); /* It's valid ... */ + if (err & ERXBUF_GOODPKT) { + len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4; + skb_trim(skb, len); + skb->protocol = eth_type_trans(skb, dev); - if ((dev->flags & IFF_ALLMULTI) || - (netdev_mc_count(dev) > 64)) { - /* Too many for hashing to make sense or we want all - multicast packets anyway, so skip computing all the - hashes and just accept all packets. */ - ip->ehar_h = 0xffffffff; - ip->ehar_l = 0xffffffff; - } else { - netdev_for_each_mc_addr(ha, dev) { - ehar |= (1UL << ioc3_hash(ha->addr)); + new_skb = ioc3_alloc_skb(dev); + if (!new_skb) { + /* Ouch, drop packet and just recycle skb + * to keep the ring filled. + */ + dev->stats.rx_dropped++; + new_skb = skb; + goto next; } - ip->ehar_h = ehar >> 32; - ip->ehar_l = ehar & 0xffffffff; + + if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS)) + ioc3_tcpudp_checksum(skb, + (w0 & ERXBUF_IPCKSUM_MASK), + len); + + netif_rx(skb); + + /* Because we reserve afterwards. */ + skb_put(new_skb, 1664); + rxb = (struct ioc3_erxbuf *)new_skb->data; + skb_reserve(new_skb, RX_OFFSET); + + dev->stats.rx_packets++; /* Statistics */ + dev->stats.rx_bytes += len; + } else { + /* The frame is invalid and the skb never + * reached the network layer so we can just + * recycle it. + */ + new_skb = skb; + dev->stats.rx_errors++; } - ioc3_w_ehar_h(ip->ehar_h); - ioc3_w_ehar_l(ip->ehar_l); + if (err & ERXBUF_CRCERR) + dev->stats.rx_crc_errors++; /* Statistics */ + if (err & ERXBUF_FRAMERR) + dev->stats.rx_frame_errors++; /* Statistics */ +next: + ip->rx_skbs[rx_entry] = new_skb; + ip->rxr[rx_entry] = cpu_to_be64(ioc3_map(rxb, PCI64_ATTR_BAR)); + rxb->w0 = 0; /* Clear valid flag */ + + /* Now go on to the next ring entry. */ + n_entry++; + n_entry &= RX_MASK; + rx_entry++; + rx_entry &= RX_MASK; + + skb = ip->rx_skbs[rx_entry]; + rxb = (struct ioc3_erxbuf *)(skb->data - RX_OFFSET); + w0 = be32_to_cpu(rxb->w0); + } + ip->rx_ci = rx_entry; + ip->rx_pi = n_entry; + writel((n_entry << 3) | ERPIR_ARM, &ip->idd->vma->erpir); +} + +static noinline void ioc3_tx(struct ioc3_private *ip, struct net_device *dev) +{ + struct sk_buff *skb; + struct ioc3 *vma = ip->idd->vma; + unsigned long packets = 0; + unsigned long bytes = 0; + int tx_entry, o_entry; + u32 etcir; + + etcir = readl(&vma->etcir); + tx_entry = (etcir >> 7) & TX_MASK; + o_entry = ip->tx_ci; + + while (o_entry != tx_entry) { + packets++; + skb = ip->tx_skbs[o_entry]; + bytes += skb->len; + dev_kfree_skb_irq(skb); + ip->tx_skbs[o_entry] = NULL; + + etcir = readl(&vma->etcir); /* More pkts sent? */ + tx_entry = (etcir >> 7) & TX_MASK; + o_entry = (o_entry + 1) & TX_MASK; /* Next */ + } + ip->tx_ci = o_entry; + + dev->stats.tx_bytes += bytes; + dev->stats.tx_packets += packets; + ip->txbfree += packets; + + if (netif_queue_stopped(dev) && (ip->txbfree > 0)) + netif_wake_queue(dev); +} + +/* The interrupt handler does all of the Rx thread work + * and cleans up after the Tx thread. + */ +static int ioc3eth_intr(struct ioc3_submodule *is, + struct ioc3_driver_data *idd, unsigned int irq) +{ + struct net_device *dev = (struct net_device *)(idd->data[is->id]); + struct ioc3_private *ip = netdev_priv(dev); + struct ioc3 *vma = idd->vma; + u32 eisr; + + spin_lock(&ip->ioc3_lock); + + eisr = readl(&vma->eisr); + + writel(eisr, &vma->eisr); + (void)readl(&vma->eisr); /* Flush */ + + if (eisr & (EISR_RXTIMERINT | EISR_RXTHRESHINT)) + ioc3_rx(ip, dev); + + if (eisr & (EISR_TXEMPTY | EISR_TXEXDEF | EISR_TXEXPLICIT)) + ioc3_tx(ip, dev); + + if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | + EISR_RXMEMERR | EISR_RXPARERR | + EISR_TXBUFUFLO | EISR_TXMEMERR)) + ioc3_error(ip, dev, eisr); + + spin_unlock(&ip->ioc3_lock); + + return 0; +} + +static int ioc3eth_probe(struct ioc3_submodule *is, + struct ioc3_driver_data *idd) +{ + struct net_device *dev; + struct ioc3_private *ip; + unsigned int sw_physid1, sw_physid2; + u32 vendor, model, rev; + int err; + + /* check for board type */ + if (idd->class == IOC3_CLASS_SERIAL) + return 1; + + dev = alloc_etherdev(sizeof(struct ioc3_private)); + if (!dev) { + err = -ENOMEM; + goto out; + } + + /* The IOC3-specific entries in the device structure. */ + dev->watchdog_timeo = 5 * HZ; + dev->netdev_ops = &ioc3_netdev_ops; + dev->ethtool_ops = &ioc3_ethtool_ops; + dev->features = NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; + + idd->data[is->id] = dev; + SET_NETDEV_DEV(dev, &idd->pdev->dev); + + if (idd->class == IOC3_CLASS_BASE_IP27 || + idd->class == IOC3_CLASS_BASE_IP30) + dev->irq = idd->pdev->irq + 2; + else + dev->irq = idd->pdev->irq; + + ip = netdev_priv(dev); + ip->idd = idd; + + spin_lock_init(&ip->ioc3_lock); + init_timer(&ip->ioc3_timer); + + ioc3_stop(ip); + ioc3_init(dev); + + ip->mii.phy_id_mask = 0x1f; + ip->mii.reg_num_mask = 0x1f; + ip->mii.dev = dev; + ip->mii.mdio_read = ioc3_mdio_read; + ip->mii.mdio_write = ioc3_mdio_write; + + ioc3_mii_init(ip); + + if (ip->mii.phy_id == -1) { + printk(KERN_CRIT "ioc3-eth(%s): Didn't find a PHY, goodbye.\n", + pci_name(idd->pdev)); + err = -ENODEV; + goto out_stop; } - netif_wake_queue(dev); /* Let us get going again. */ + ioc3_mii_start(ip); + ioc3_ssram_disc(ip); + ioc3_get_eaddr(idd, dev); + + sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); + sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); + + err = register_netdev(dev); + if (err) + goto out_stop; + + mii_check_media(&ip->mii, 1, 1); + ioc3_setup_duplex(ip); + + vendor = (sw_physid1 << 12) | (sw_physid2 >> 4); + model = (sw_physid2 >> 4) & 0x3f; + rev = sw_physid2 & 0xf; + printk(KERN_INFO "%s: Using PHY %d, vendor 0x%x, model %d, " + "rev %d.\n", dev->name, ip->mii.phy_id, vendor, model, rev); + printk(KERN_INFO "%s: IOC3 SSRAM has %d kbyte.\n", dev->name, + ip->emcr & EMCR_BUFSIZ ? 128 : 64); + + return 0; + +out_stop: + ioc3_stop(ip); + del_timer_sync(&ip->ioc3_timer); + ioc3_free_rings(ip); + free_netdev(dev); +out: + return err; } -module_pci_driver(ioc3_driver); +static int ioc3eth_remove(struct ioc3_submodule *is, + struct ioc3_driver_data *idd) +{ + struct net_device *dev = idd->data[is->id]; + struct ioc3_private *ip = netdev_priv(dev); + + unregister_netdev(dev); + del_timer_sync(&ip->ioc3_timer); + ioc3_free_rings(ip); + free_netdev(dev); + + return 0; +} + +static struct ioc3_submodule ioc3eth_driver = { + .name = "Ethernet", + .probe = ioc3eth_probe, + .remove = ioc3eth_remove, + .ethernet = 1, + .intr = ioc3eth_intr, + .owner = THIS_MODULE, +}; + +ioc3_submodule_driver(ioc3eth_driver); + MODULE_AUTHOR("Ralf Baechle "); MODULE_DESCRIPTION("SGI IOC3 Ethernet driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig deleted file mode 100644 index c66ba9a..0000000 --- a/drivers/sn/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# 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 693db8b..0000000 --- a/drivers/sn/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# 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 fb7ea0d..0000000 --- a/drivers/sn/ioc3.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * SGI IOC3 master driver and IRQ demuxer - * - * Copyright (c) 2005 Stanislaw Skowronek - * Heavily based on similar work by: - * Brent Casavant - IOC4 master driver - * Pat Gefre - IOC3 serial port IRQ demuxer - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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;idactive[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;iethernet) { - 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;idprobe) { - 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;idactive[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 "); -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/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c new file mode 100644 index 0000000..8796772 --- /dev/null +++ b/drivers/tty/serial/8250/8250_ioc3.c @@ -0,0 +1,132 @@ +/* + * SGI IOC3 bridge for UARTs + * + * Copyright (C) 2005 Stanislaw Skowronek + * Copyright (C) 2014 Joshua Kinard + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "8250.h" + +#define IOC3_UARTCLK (22000000 / 3) + +extern int create_dynamic_irq(void); +extern void destroy_dynamic_irq(int irq); +extern void do_dynamic_irq(int irq); + +struct ioc3uart_data { + int line_a, line_b; + int irq; +}; + +static int +serial8250_ioc3_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) +{ + struct uart_8250_port up; + struct ioc3uart_data *d; + + /* Check for UART-less add-on boards */ + if (idd->class == IOC3_CLASS_MENET_4 || + idd->class == IOC3_CLASS_CADDUO) + return 1; + + /* Set PIO mode for SuperIO UARTs. */ + ioc3_gpcr_set(idd, (GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL)); + idd->vma->gppr[6] = 0; + idd->vma->gppr[7] = 0; + udelay(1000); + idd->vma->port_a.sscr &= ~(SSCR_DMA_EN); + idd->vma->port_b.sscr &= ~(SSCR_DMA_EN); + udelay(1000); + + /* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */ + idd->vma->sio_iec = (SIO_IR_SA_TX_MT | SIO_IR_SB_TX_MT | + SIO_IR_SA_RX_FULL | SIO_IR_SB_RX_FULL | + SIO_IR_SA_RX_HIGH | SIO_IR_SB_RX_HIGH | + SIO_IR_SA_RX_TIMER | SIO_IR_SB_RX_TIMER | + SIO_IR_SA_DELTA_DCD | SIO_IR_SB_DELTA_DCD | + SIO_IR_SA_DELTA_CTS | SIO_IR_SB_DELTA_CTS | + SIO_IR_SA_TX_EXPLICIT | SIO_IR_SB_TX_EXPLICIT | + SIO_IR_SA_MEMERR | SIO_IR_SB_MEMERR); + idd->vma->sio_ies = (SIO_IR_SA_INT | SIO_IR_SB_INT); + udelay(1000); + + idd->vma->sregs.uarta.iu_fcr = 0; + idd->vma->sregs.uartb.iu_fcr = 0; + udelay(1000); + + /* Assign IRQ0 to cause 8250_core.c to use a timer to poll the port */ + d = devm_kzalloc(&idd->pdev->dev, sizeof(struct ioc3uart_data), + GFP_KERNEL); + d->irq = 0; + idd->data[is->id] = d; + + /* Register serial ports with 8250.c */ + memset(&up, 0, sizeof(struct uart_8250_port)); + up.port.iotype = UPIO_IOC3; + up.port.uartclk = IOC3_UARTCLK; + up.port.type = PORT_16550A; + up.port.irq = d->irq; + up.port.flags = (UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ); + up.port.regshift = 0; + up.port.dev = &idd->pdev->dev; + + up.port.membase = (unsigned char *)&idd->vma->sregs.uarta; + up.port.mapbase = (((unsigned long)up.port.membase) & 0xffffffffff); + d->line_a = serial8250_register_8250_port(&up); + + up.port.membase = (unsigned char *)&idd->vma->sregs.uartb; + up.port.mapbase = (((unsigned long)up.port.membase) & 0xffffffffff); + d->line_b = serial8250_register_8250_port(&up); + + ioc3_enable(is, idd, is->irq_mask); + return 0; +} + +static int +serial8250_ioc3_remove(struct ioc3_submodule *is, struct ioc3_driver_data *idd) +{ + struct ioc3uart_data *d = (struct ioc3uart_data *)(idd->data[is->id]); + + ioc3_disable(is, idd, is->irq_mask); + serial8250_unregister_port(d->line_a); + serial8250_unregister_port(d->line_b); + idd->data[is->id] = NULL; + return 0; +} + +static struct +ioc3_submodule ioc3uart_submodule = { + .name = "uart", + .probe = serial8250_ioc3_probe, + .remove = serial8250_ioc3_remove, + .irq_mask = SIO_IR_SA_INT | SIO_IR_SB_INT, + .reset_mask = 1, + .owner = THIS_MODULE, +}; + +ioc3_submodule_driver(ioc3uart_submodule); + +MODULE_AUTHOR("Stanislaw Skowronek "); +MODULE_AUTHOR("Joshua Kinard "); +MODULE_DESCRIPTION("SGI IOC3 8250 UART driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.42.1"); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 52d82d2..f1f5e1f 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -342,6 +342,20 @@ static void au_serial_dl_write(struct uart_8250_port *up, int value) #endif +#if defined(CONFIG_SGI_IOC3) || defined(CONFIG_SERIAL_8250_IOC3) +static unsigned int ioc3_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readb(p->membase + (offset ^ 3)); +} + +static void ioc3_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + writeb(value, p->membase + (offset ^ 3)); +} +#endif + static unsigned int hub6_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -444,6 +458,13 @@ static void set_io_from_upio(struct uart_port *p) break; #endif +#if defined(CONFIG_SGI_IOC3) || defined(CONFIG_SERIAL_8250_IOC3) + case UPIO_IOC3: + p->serial_in = ioc3_serial_in; + p->serial_out = ioc3_serial_out; + break; +#endif + default: p->serial_in = io_serial_in; p->serial_out = io_serial_out; @@ -462,6 +483,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value) case UPIO_MEM32: case UPIO_MEM32BE: case UPIO_AU: + case UPIO_IOC3: p->serial_out(p, offset, value); p->serial_in(p, UART_LCR); /* safe, no side-effects */ break; @@ -2485,6 +2507,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) if (!request_region(port->iobase, size, "serial")) ret = -EBUSY; break; + case UPIO_IOC3: + break; } return ret; } @@ -2515,6 +2539,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) case UPIO_PORT: release_region(port->iobase, size); break; + case UPIO_IOC3: + break; } } diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 6412f14..ac99957 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -292,6 +292,17 @@ config SERIAL_8250_EM port hardware found on the Emma Mobile line of processors. If unsure, say N. +config SERIAL_8250_IOC3 + tristate "SGI IOC3 8250 UART support" + depends on SGI_IOC3 && SERIAL_8250 + select SERIAL_8250_EXTENDED + select SERIAL_8250_SHARE_IRQ + help + Enable this if you have a SGI Origin or Octane machine. This module + provides basic serial support by directly driving the UART chip + behind the IOC3 device on those systems. Maximum baud speed is + 38400bps using this driver. + config SERIAL_8250_RT288X bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" depends on SERIAL_8250 diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index e177f86..841c00c 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o +obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index f38beb2..7b052f8 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1036,8 +1036,8 @@ config SERIAL_SGI_IOC4 Otherwise, say N. config SERIAL_SGI_IOC3 - tristate "SGI Altix IOC3 serial support" - depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3 + tristate "SGI IOC3 serial support" + depends on SGI_IOC3 select SERIAL_CORE help If you have an SGI Altix with an IOC3 serial card, diff --git a/drivers/tty/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c index 27b5fef..258abd3 100644 --- a/drivers/tty/serial/ioc3_serial.c +++ b/drivers/tty/serial/ioc3_serial.c @@ -23,6 +23,9 @@ #include #include +#include +#include + /* * Interesting things about the ioc3 */ @@ -36,7 +39,6 @@ /* 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 @@ -50,11 +52,14 @@ 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__) +#define DEBUG_INTERRUPTS +#if DEBUG + #define DPRINT_CONFIG(_x...) (printk _x) + #define NOT_PROGRESS() (printk("%s : fails %d\n", __func__, __LINE__)) +#else + #define DPRINT_CONFIG(_x...) ; + #define NOT_PROGRESS() ; +#endif /* number of characters we want to transmit to the lower level at a time */ #define MAX_CHARS 256 @@ -119,6 +124,18 @@ static unsigned int Submodule_slot; #define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4) + +static unsigned long ioc3_map(void *ptr, unsigned long dma_attr) +{ +#if defined(CONFIG_SGI_IP27) + return (0xaUL << PCI64_ATTR_TARG_SHFT) | dma_attr | + ((unsigned long)ptr & TO_PHYS_MASK); +#else + return virt_to_bus(ptr); +#endif +} + + /* driver specific - one per card */ struct ioc3_card { struct { @@ -301,17 +318,17 @@ struct ring_buffer { /** - * set_baud - Baud rate setting code + * ioc3_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) +static int ioc3_set_baud(struct ioc3_port *port, int baud) { + struct ioc3_uartregs __iomem *uart; 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)); @@ -349,10 +366,10 @@ static int set_baud(struct ioc3_port *port, int baud) } /** - * get_ioc3_port - given a uart port, return the control structure + * ioc3_get_ioc3port - 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) +static struct ioc3_port *ioc3_get_ioc3port(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]; @@ -373,17 +390,17 @@ static struct ioc3_port *get_ioc3_port(struct uart_port *the_port) } /** - * port_init - Initialize the sio and ioc3 hardware for a given port + * ioc3_port_init - Initialize the sio and ioc3 hardware for a given port * called per port from attach... * @port: port to initialize */ -static int inline port_init(struct ioc3_port *port) +static int ioc3_port_init(struct ioc3_port *port) { - uint32_t sio_cr; struct port_hooks *hooks = port->ip_hooks; + struct ioc3_driver_data *idd = port->ip_idd; struct ioc3_uartregs __iomem *uart; int reset_loop_counter = 0xfffff; - struct ioc3_driver_data *idd = port->ip_idd; + uint32_t sio_cr; /* Idle the IOC3 serial interface */ writel(SSCR_RESET, &port->ip_serial_regs->sscr); @@ -420,7 +437,7 @@ static int inline port_init(struct ioc3_port *port) writeb(0, &uart->iu_ier); /* Set the default baud */ - set_baud(port, port->ip_baud); + ioc3_set_baud(port, port->ip_baud); /* Set line control to 8 bits no parity */ writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr); @@ -445,7 +462,8 @@ static int inline port_init(struct ioc3_port *port) sbbr_l = &idd->vma->sbbr_l; sbbr_h = &idd->vma->sbbr_h; - ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf; +// ring_pci_addr = ioc3_map((unsigned long __iomem)port->ip_dma_ringbuf, PCI64_ATTR_BAR); + ring_pci_addr = ioc3_map(&port->ip_dma_ringbuf, PCI64_ATTR_BAR); DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n", __func__, (void *)ring_pci_addr)); @@ -477,11 +495,11 @@ static int inline port_init(struct ioc3_port *port) } /** - * enable_intrs - enable interrupts + * ioc3_uart_enable_intrs - enable interrupts * @port: port to enable * @mask: mask to use */ -static void enable_intrs(struct ioc3_port *port, uint32_t mask) +static void ioc3_uart_enable_intrs(struct ioc3_port *port, uint32_t mask) { if ((port->ip_card->ic_enable & mask) != mask) { port->ip_card->ic_enable |= mask; @@ -490,10 +508,10 @@ static void enable_intrs(struct ioc3_port *port, uint32_t mask) } /** - * local_open - local open a port + * ioc3_local_open - local open a port * @port: port to open */ -static inline int local_open(struct ioc3_port *port) +static int ioc3_local_open(struct ioc3_port *port) { int spiniter = 0; @@ -539,11 +557,11 @@ static inline int local_open(struct ioc3_port *port) } /** - * set_rx_timeout - Set rx timeout and threshold values. + * ioc3_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) +static int ioc3_set_rx_timeout(struct ioc3_port *port, int timeout) { int threshold; @@ -578,7 +596,7 @@ static inline int set_rx_timeout(struct ioc3_port *port, int timeout) } /** - * config_port - config the hardware + * ioc3_config_port - config the hardware * @port: port to config * @baud: baud rate for the port * @byte_size: data size @@ -586,19 +604,18 @@ static inline int set_rx_timeout(struct ioc3_port *port, int timeout) * @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) +static int ioc3_config_port(struct ioc3_port *port, int baud, int byte_size, + int stop_bits, int parenb, int parodd) { - char lcr, sizebits; int spiniter = 0; + char lcr, sizebits; 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)) + if (ioc3_set_baud(port, baud)) return 1; switch (byte_size) { @@ -665,23 +682,23 @@ config_port(struct ioc3_port *port, if (port->ip_tx_lowat == 0) port->ip_tx_lowat = 1; - set_rx_timeout(port, 2); + ioc3_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 + * ioc3_do_write - Write bytes to the port. Returns the number of bytes + * actually written. Called from ioc3_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) +static int ioc3_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; + struct ring *outring; + int prod_ptr, cons_ptr, total = 0; BUG_ON(!(len >= 0)); @@ -747,7 +764,7 @@ static inline int do_write(struct ioc3_port *port, char *buf, int len) * can disable DMA if necessary when the tx finishes. */ if (total > 0) - enable_intrs(port, hooks->intr_tx_mt); + ioc3_uart_enable_intrs(port, hooks->intr_tx_mt); } port->ip_tx_prod = prod_ptr; @@ -755,11 +772,11 @@ static inline int do_write(struct ioc3_port *port, char *buf, int len) } /** - * disable_intrs - disable interrupts + * ioc3_uart_disable_intrs - disable interrupts * @port: port to enable * @mask: mask to use */ -static inline void disable_intrs(struct ioc3_port *port, uint32_t mask) +static void ioc3_uart_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); @@ -768,12 +785,12 @@ static inline void disable_intrs(struct ioc3_port *port, uint32_t mask) } /** - * set_notification - Modify event notification + * ioc3_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) +static int ioc3_set_notification(struct ioc3_port *port, int mask, int set_on) { struct port_hooks *hooks = port->ip_hooks; uint32_t intrbits, sscrbits; @@ -794,11 +811,11 @@ static int set_notification(struct ioc3_port *port, int mask, int set_on) intrbits |= hooks->intr_delta_cts; if (set_on) { - enable_intrs(port, intrbits); + ioc3_uart_enable_intrs(port, intrbits); port->ip_notify |= mask; port->ip_sscr |= sscrbits; } else { - disable_intrs(port, intrbits); + ioc3_uart_disable_intrs(port, intrbits); port->ip_notify &= ~mask; port->ip_sscr &= ~sscrbits; } @@ -817,15 +834,14 @@ static int set_notification(struct ioc3_port *port, int mask, int set_on) } /** - * set_mcr - set the master control reg + * ioc3_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) +static int ioc3_set_mcr(struct uart_port *the_port, int mask1, int mask2) { - struct ioc3_port *port = get_ioc3_port(the_port); + struct ioc3_port *port = ioc3_get_ioc3port(the_port); uint32_t shadow; int spiniter = 0; char mcr; @@ -889,17 +905,17 @@ static int ioc3_set_proto(struct ioc3_port *port, int proto) } /** - * transmit_chars - upper level write, called with the_port->lock + * ioc3_transmit_chars - upper level write, called with the_port->lock * @the_port: port to write */ -static void transmit_chars(struct uart_port *the_port) +static void ioc3_transmit_chars(struct uart_port *the_port) { + struct ioc3_port *port = ioc3_get_ioc3port(the_port); + struct uart_state *state; + struct tty_struct *tty; + char *start; 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; @@ -911,7 +927,7 @@ static void transmit_chars(struct uart_port *the_port) if (uart_circ_empty(&state->xmit) || uart_tx_stopped(the_port)) { /* Nothing to do or hw stopped */ - set_notification(port, N_ALL_OUTPUT, 0); + ioc3_set_notification(port, N_ALL_OUTPUT, 0); return; } @@ -922,7 +938,7 @@ static void transmit_chars(struct uart_port *the_port) /* 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); + result = ioc3_do_write(port, start, xmit_count); if (result > 0) { /* booking */ xmit_count -= result; @@ -937,11 +953,10 @@ static void transmit_chars(struct uart_port *the_port) 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); - } + if (uart_circ_empty(&state->xmit)) + ioc3_set_notification(port, N_OUTPUT_LOWAT, 0); + else + ioc3_set_notification(port, N_OUTPUT_LOWAT, 1); } /** @@ -950,15 +965,14 @@ static void transmit_chars(struct uart_port *the_port) * @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) +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); + struct ioc3_port *port = ioc3_get_ioc3port(the_port); + struct uart_state *state = the_port->state; + int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; 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; @@ -1027,26 +1041,26 @@ ioc3_change_speed(struct uart_port *the_port, /* 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 " + "ioc3_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 */ + if ((ioc3_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); + ioc3_set_notification(port, the_port->ignore_status_mask, 1); } } /** - * ic3_startup_local - Start up the serial port - returns >= 0 if no errors + * ioc3_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) +static int ioc3_startup_local(struct uart_port *the_port) { struct ioc3_port *port; @@ -1055,13 +1069,13 @@ static inline int ic3_startup_local(struct uart_port *the_port) return -1; } - port = get_ioc3_port(the_port); + port = ioc3_get_ioc3port(the_port); if (!port) { NOT_PROGRESS(); return -1; } - local_open(port); + ioc3_local_open(port); /* set the protocol */ ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 : @@ -1075,13 +1089,11 @@ static inline int ic3_startup_local(struct uart_port *the_port) */ 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); + spin_lock(&port->ip_port->lock); + ioc3_transmit_chars(port->ip_port); + spin_unlock(&port->ip_port->lock); } } @@ -1107,17 +1119,17 @@ static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs) } /** - * do_read - Read in bytes from the port. Return the number of bytes + * ioc3_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) +static int ioc3_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 ioc3_port *port = ioc3_get_ioc3port(the_port); struct ring *inring; struct ring_entry *entry; struct port_hooks *hooks; @@ -1382,21 +1394,21 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len) SSCR_RX_THRESHOLD) << PROD_CONS_PTR_OFF))) { port->ip_flags &= ~INPUT_HIGH; - enable_intrs(port, hooks->intr_rx_high); + ioc3_uart_enable_intrs(port, hooks->intr_rx_high); } return total; } /** - * receive_chars - upper level read. + * ioc3_receive_chars - upper level read. * @the_port: port to read from */ -static int receive_chars(struct uart_port *the_port) +static int ioc3_receive_chars(struct uart_port *the_port) { + struct ioc3_port *port = ioc3_get_ioc3port(the_port); + struct uart_state *state = the_port->state; 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 */ @@ -1408,7 +1420,7 @@ static int receive_chars(struct uart_port *the_port) spin_lock_irqsave(&the_port->lock, pflags); - read_count = do_read(the_port, ch, MAX_CHARS); + read_count = ioc3_do_read(the_port, ch, MAX_CHARS); if (read_count > 0) { flip = 1; read_room = tty_insert_flip_string(&state->port, ch, @@ -1424,26 +1436,22 @@ static int receive_chars(struct uart_port *the_port) } /** - * ioc3uart_intr_one - lowest level (per port) interrupt handler. + * ioc3_uart_intr_one - lowest level (per port) interrupt handler. * @is : submodule * @idd: driver data * @pending: interrupts to handle */ -static int inline -ioc3uart_intr_one(struct ioc3_submodule *is, - struct ioc3_driver_data *idd, - unsigned int pending) +static int ioc3_uart_intr_one(struct ioc3_submodule *is, struct ioc3_driver_data *idd, + unsigned int pending) { - int port_num = GET_PORT_FROM_SIO_IR(pending); + struct ioc3_card *card_ptr; + struct ioc3_port *port; struct port_hooks *hooks; - unsigned int rx_high_rd_aborted = 0; - unsigned long flags; struct uart_port *the_port; - struct ioc3_port *port; + unsigned int sio_ir, rx_high_rd_aborted = 0; + int port_num = GET_PORT_FROM_SIO_IR(pending); 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; @@ -1465,14 +1473,14 @@ ioc3uart_intr_one(struct ioc3_submodule *is, */ sio_ir = pending & ~(hooks->intr_tx_mt); - spin_lock_irqsave(&port->ip_lock, flags); + spin_lock(&port->ip_lock); loop_counter = MAXITER; /* to avoid hangs */ do { uint32_t shadow; - if (loop_counter-- <= 0) { + if (unlikely(loop_counter-- <= 0)) { printk(KERN_WARNING "IOC3 serial: " "possible hang condition/" "port stuck on interrupt (line %d).\n", @@ -1480,7 +1488,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, break; } /* Handle a DCD change */ - if (sio_ir & hooks->intr_delta_dcd) { + if (unlikely(sio_ir & hooks->intr_delta_dcd)) { ioc3_ack(is, idd, hooks->intr_delta_dcd); shadow = readl(&port->ip_serial_regs->shadow); @@ -1502,7 +1510,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, } /* Handle a CTS change */ - if (sio_ir & hooks->intr_delta_cts) { + if (unlikely(sio_ir & hooks->intr_delta_cts)) { ioc3_ack(is, idd, hooks->intr_delta_cts); shadow = readl(&port->ip_serial_regs->shadow); @@ -1519,22 +1527,22 @@ ioc3uart_intr_one(struct ioc3_submodule *is, * before the check for rx_high since servicing this condition * may cause that condition to clear. */ - if (sio_ir & hooks->intr_rx_timer) { + if (unlikely(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); + ioc3_receive_chars(port->ip_port); } } /* rx high interrupt. Must be after rx_timer. */ - else if (sio_ir & hooks->intr_rx_high) { + else if (unlikely(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); + ioc3_receive_chars(port->ip_port); } - /* We can't ACK this interrupt. If receive_chars didn't + /* We can't ACK this interrupt. If ioc3_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 @@ -1559,7 +1567,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, * 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) { + if (unlikely(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) @@ -1567,7 +1575,7 @@ ioc3uart_intr_one(struct ioc3_submodule *is, } /* Handle tx_mt. Must come after tx_explicit. */ - else if (sio_ir & hooks->intr_tx_mt) { + else if (unlikely(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 @@ -1617,20 +1625,20 @@ ioc3uart_intr_one(struct ioc3_submodule *is, } } while (sio_ir & hooks->intr_all); - spin_unlock_irqrestore(&port->ip_lock, flags); + spin_unlock(&port->ip_lock); ioc3_enable(is, idd, card_ptr->ic_enable); return 0; } /** - * ioc3uart_intr - field all serial interrupts + * ioc3_uart_intr - field all serial interrupts * @is : submodule * @idd: driver data * @pending: interrupts to handle * */ -static int ioc3uart_intr(struct ioc3_submodule *is, +static int ioc3_uart_intr(struct ioc3_submodule *is, struct ioc3_driver_data *idd, unsigned int pending) { @@ -1642,19 +1650,19 @@ static int ioc3uart_intr(struct ioc3_submodule *is, */ if (pending & SIO_IR_SA) - ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA); + ret |= ioc3_uart_intr_one(is, idd, pending & SIO_IR_SA); if (pending & SIO_IR_SB) - ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB); + ret |= ioc3_uart_intr_one(is, idd, pending & SIO_IR_SB); return ret; } /** - * ic3_type + * ioc3_type * @port: Port to operate with (we ignore since we only have one port) * */ -static const char *ic3_type(struct uart_port *the_port) +static const char *ioc3_type(struct uart_port *the_port) { if (IS_RS232(the_port->line)) return "SGI IOC3 Serial [rs232]"; @@ -1663,14 +1671,14 @@ static const char *ic3_type(struct uart_port *the_port) } /** - * ic3_tx_empty - Is the transmitter empty? + * ioc3_tx_empty - Is the transmitter empty? * @port: Port to operate on * */ -static unsigned int ic3_tx_empty(struct uart_port *the_port) +static unsigned int ioc3_tx_empty(struct uart_port *the_port) { + struct ioc3_port *port = ioc3_get_ioc3port(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; @@ -1678,52 +1686,52 @@ static unsigned int ic3_tx_empty(struct uart_port *the_port) } /** - * ic3_stop_tx - stop the transmitter + * ioc3_stop_tx - stop the transmitter * @port: Port to operate on * */ -static void ic3_stop_tx(struct uart_port *the_port) +static void ioc3_stop_tx(struct uart_port *the_port) { - struct ioc3_port *port = get_ioc3_port(the_port); + struct ioc3_port *port = ioc3_get_ioc3port(the_port); if (port) - set_notification(port, N_OUTPUT_LOWAT, 0); + ioc3_set_notification(port, N_OUTPUT_LOWAT, 0); } /** - * ic3_stop_rx - stop the receiver + * ioc3_stop_rx - stop the receiver * @port: Port to operate on * */ -static void ic3_stop_rx(struct uart_port *the_port) +static void ioc3_stop_rx(struct uart_port *the_port) { - struct ioc3_port *port = get_ioc3_port(the_port); + struct ioc3_port *port = ioc3_get_ioc3port(the_port); if (port) port->ip_flags &= ~INPUT_ENABLE; } /** - * null_void_function + * ioc3_null_void_function * @port: Port to operate on * */ -static void null_void_function(struct uart_port *the_port) +static void ioc3_null_void_function(struct uart_port *the_port) { } /** - * ic3_shutdown - shut down the port - free irq and disable + * ioc3_shutdown - shut down the port - free irq and disable * @port: port to shut down * */ -static void ic3_shutdown(struct uart_port *the_port) +static void ioc3_shutdown(struct uart_port *the_port) { - unsigned long port_flags; struct ioc3_port *port; struct uart_state *state; + unsigned long port_flags; - port = get_ioc3_port(the_port); + port = ioc3_get_ioc3port(the_port); if (!port) return; @@ -1731,17 +1739,17 @@ static void ic3_shutdown(struct uart_port *the_port) wake_up_interruptible(&state->port.delta_msr_wait); spin_lock_irqsave(&the_port->lock, port_flags); - set_notification(port, N_ALL, 0); + ioc3_set_notification(port, N_ALL, 0); spin_unlock_irqrestore(&the_port->lock, port_flags); } /** - * ic3_set_mctrl - set control lines (dtr, rts, etc) + * ioc3_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) +static void ioc3_set_mctrl(struct uart_port *the_port, unsigned int mctrl) { unsigned char mcr = 0; @@ -1756,17 +1764,17 @@ static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; - set_mcr(the_port, mcr, SHADOW_DTR); + ioc3_set_mcr(the_port, mcr, SHADOW_DTR); } /** - * ic3_get_mctrl - get control line info + * ioc3_get_mctrl - get control line info * @port: port to operate on * */ -static unsigned int ic3_get_mctrl(struct uart_port *the_port) +static unsigned int ioc3_get_mctrl(struct uart_port *the_port) { - struct ioc3_port *port = get_ioc3_port(the_port); + struct ioc3_port *port = ioc3_get_ioc3port(the_port); uint32_t shadow; unsigned int ret = 0; @@ -1784,47 +1792,47 @@ static unsigned int ic3_get_mctrl(struct uart_port *the_port) } /** - * ic3_start_tx - Start transmitter. Called with the_port->lock + * ioc3_start_tx - Start transmitter. Called with the_port->lock * @port: Port to operate on * */ -static void ic3_start_tx(struct uart_port *the_port) +static void ioc3_start_tx(struct uart_port *the_port) { - struct ioc3_port *port = get_ioc3_port(the_port); + struct ioc3_port *port = ioc3_get_ioc3port(the_port); if (port) { - set_notification(port, N_OUTPUT_LOWAT, 1); - enable_intrs(port, port->ip_hooks->intr_tx_mt); + ioc3_set_notification(port, N_OUTPUT_LOWAT, 1); + ioc3_uart_enable_intrs(port, port->ip_hooks->intr_tx_mt); } } /** - * ic3_break_ctl - handle breaks + * ioc3_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) +static void ioc3_break_ctl(struct uart_port *the_port, int break_state) { } /** - * ic3_startup - Start up the serial port - always return 0 (We're always on) + * ioc3_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) +static int ioc3_startup(struct uart_port *the_port) { - int retval; struct ioc3_port *port; struct ioc3_card *card_ptr; unsigned long port_flags; + int retval; if (!the_port) { NOT_PROGRESS(); return -ENODEV; } - port = get_ioc3_port(the_port); + port = ioc3_get_ioc3port(the_port); if (!port) { NOT_PROGRESS(); return -ENODEV; @@ -1839,21 +1847,21 @@ static int ic3_startup(struct uart_port *the_port) /* Start up the serial port */ spin_lock_irqsave(&the_port->lock, port_flags); - retval = ic3_startup_local(the_port); + retval = ioc3_startup_local(the_port); spin_unlock_irqrestore(&the_port->lock, port_flags); return retval; } /** - * ic3_set_termios - set termios stuff + * ioc3_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) +static void ioc3_set_termios(struct uart_port *the_port, + struct ktermios *termios, + struct ktermios *old_termios) { unsigned long port_flags; @@ -1863,30 +1871,31 @@ ic3_set_termios(struct uart_port *the_port, } /** - * ic3_request_port - allocate resources for port - no op.... + * ioc3_request_port - allocate resources for port - no op.... * @port: port to operate on * */ -static int ic3_request_port(struct uart_port *port) +static int ioc3_request_port(struct uart_port *port) { return 0; } /* Associate the uart functions above - given to serial core */ static 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, + .tx_empty = ioc3_tx_empty, + .set_mctrl = ioc3_set_mctrl, + .get_mctrl = ioc3_get_mctrl, + .stop_tx = ioc3_stop_tx, + .start_tx = ioc3_start_tx, + .stop_rx = ioc3_stop_rx, + .enable_ms = ioc3_null_void_function, + .break_ctl = ioc3_break_ctl, + .startup = ioc3_startup, + .shutdown = ioc3_shutdown, + .set_termios = ioc3_set_termios, + .type = ioc3_type, + .release_port = ioc3_null_void_function, + .request_port = ioc3_request_port, }; /* @@ -1904,18 +1913,18 @@ static struct uart_driver ioc3_uart = { /** * ioc3_serial_core_attach - register with serial core - * This is done during pci probing + * 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) +static 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_port *port; struct ioc3_card *card_ptr = idd->data[is->id]; - int ii, phys_port; struct pci_dev *pdev = idd->pdev; + int ii, phys_port; DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n", __func__, pdev, (void *)card_ptr)); @@ -1963,13 +1972,13 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is, } /** - * ioc3uart_remove - register detach function + * ioc3_uart_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) +static int ioc3_uart_remove(struct ioc3_submodule *is, + struct ioc3_driver_data *idd) { struct ioc3_card *card_ptr = idd->data[is->id]; struct uart_port *the_port; @@ -2001,21 +2010,21 @@ static int ioc3uart_remove(struct ioc3_submodule *is, } /** - * ioc3uart_probe - card probe function called from shim driver + * ioc3_uart_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) +static int ioc3_uart_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]; + struct ioc3_port *port; + struct ioc3_card *card_ptr; int phys_port; int cnt; + int ret = 0; DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd)); @@ -2032,8 +2041,6 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) ((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); @@ -2124,7 +2131,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) (void *)port->ip_uart_regs)); /* Initialize the hardware for IOC3 */ - port_init(port); + ioc3_port_init(port); DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p " "outring 0x%p\n", @@ -2154,20 +2161,20 @@ out4: return ret; } -static struct ioc3_submodule ioc3uart_ops = { +static struct ioc3_submodule ioc3_uart_ops = { .name = "IOC3uart", - .probe = ioc3uart_probe, - .remove = ioc3uart_remove, + .probe = ioc3_uart_probe, + .remove = ioc3_uart_remove, /* call .intr for both ports initially */ .irq_mask = SIO_IR_SA | SIO_IR_SB, - .intr = ioc3uart_intr, + .intr = ioc3_uart_intr, .owner = THIS_MODULE, }; /** * ioc3_detect - module init called, */ -static int __init ioc3uart_init(void) +static int __init ioc3_uart_init(void) { int ret; @@ -2178,20 +2185,20 @@ static int __init ioc3uart_init(void) __func__); return ret; } - ret = ioc3_register_submodule(&ioc3uart_ops); + ret = ioc3_register_submodule(&ioc3_uart_ops); if (ret) uart_unregister_driver(&ioc3_uart); return ret; } -static void __exit ioc3uart_exit(void) +static void __exit ioc3_uart_exit(void) { - ioc3_unregister_submodule(&ioc3uart_ops); + ioc3_unregister_submodule(&ioc3_uart_ops); uart_unregister_driver(&ioc3_uart); } -module_init(ioc3uart_init); -module_exit(ioc3uart_exit); +module_init(ioc3_uart_init); +module_exit(ioc3_uart_exit); MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) "); MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card"); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index def5199..95901e4 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2193,6 +2193,10 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) snprintf(address, sizeof(address), "MMIO 0x%llx", (unsigned long long)port->mapbase); break; + case UPIO_IOC3: + snprintf(address, sizeof(address), "IOC3 0x%llx", + (unsigned long long)port->mapbase); + break; default: strlcpy(address, "*unknown*", sizeof(address)); break; @@ -2835,6 +2839,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: + case UPIO_IOC3: return (port1->mapbase == port2->mapbase); } return 0; diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h index 38b286e9..775c8d5 100644 --- a/include/linux/ioc3.h +++ b/include/linux/ioc3.h @@ -3,15 +3,16 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 2005 Stanislaw Skowronek + * Copyright (c) 2005 Stanislaw Skowronek */ #ifndef _LINUX_IOC3_H #define _LINUX_IOC3_H -#include +#include +#include -#define IOC3_MAX_SUBMODULES 32 +#define IOC3_MAX_SUBMODULES 8 #define IOC3_CLASS_NONE 0 #define IOC3_CLASS_BASE_IP27 1 @@ -25,22 +26,22 @@ struct ioc3_driver_data { struct list_head list; int id; /* IOC3 sequence number */ + int class; /* IOC3 type */ + /* PCI mapping */ - unsigned long pma; /* physical address */ struct ioc3 __iomem *vma; /* pointer to registers */ struct pci_dev *pdev; /* PCI device */ /* IRQ stuff */ int dual_irq; /* set if separate IRQs are used */ int irq_io, irq_eth; /* IRQ numbers */ /* GPIO magic */ - spinlock_t gpio_lock; unsigned int gpdr_shadow; + spinlock_t gpio_lock; /* NIC identifiers */ char nic_part[32]; char nic_serial[16]; char nic_mac[6]; /* submodule set */ - int class; void *data[IOC3_MAX_SUBMODULES]; /* for submodule use */ int active[IOC3_MAX_SUBMODULES]; /* set if probe succeeds */ /* is_ir_lock must be held while @@ -56,10 +57,10 @@ struct ioc3_driver_data { struct ioc3_submodule { char *name; /* descriptive submodule name */ struct module *owner; /* owning kernel module */ - int ethernet; /* set for ethernet drivers */ int (*probe) (struct ioc3_submodule *, struct ioc3_driver_data *); int (*remove) (struct ioc3_submodule *, struct ioc3_driver_data *); int id; /* assigned by IOC3, index for the "data" array */ + int ethernet; /* set for ethernet drivers */ /* IRQ stuff */ unsigned int irq_mask; /* IOC3 IRQ mask, leave clear for Ethernet */ int reset_mask; /* non-zero if you want the ioc3.c module to reset interrupts */ @@ -89,5 +90,17 @@ extern void ioc3_disable(struct ioc3_submodule *, struct ioc3_driver_data *, uns extern void ioc3_gpcr_set(struct ioc3_driver_data *, unsigned int); /* general ireg writer */ extern void ioc3_write_ireg(struct ioc3_driver_data *idd, uint32_t value, int reg); +/* atomically sets/clears GPIO bits */ +extern void ioc3_gpio(struct ioc3_driver_data *, unsigned int, unsigned int); + +/* + * ioc3_submodule_driver() - Helper macro for ioc3 submodules that don't do + * anything special in module init/exit. This eliminates a bit of + * boilerplate. Each submodule may only use this macro once, and calling it + * replaces ioc3_register_submodule() and ioc3_unregister_submodule() + */ +#define ioc3_submodule_driver(__ioc3_submodule) \ + module_driver(__ioc3_submodule, ioc3_register_submodule, \ + ioc3_unregister_submodule) #endif diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 297d4fa..c403030 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -150,6 +150,7 @@ struct uart_port { #define UPIO_AU (SERIAL_IO_AU) /* Au1x00 and RT288x type IO */ #define UPIO_TSI (SERIAL_IO_TSI) /* Tsi108/109 type IO */ #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */ +#define UPIO_IOC3 (SERIAL_IO_IOC3) /* SGI IOC3 IO */ unsigned int read_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */ diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h index 25331f9..cef32e4 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -69,6 +69,7 @@ struct serial_struct { #define SERIAL_IO_AU 4 #define SERIAL_IO_TSI 5 #define SERIAL_IO_MEM32BE 6 +#define SERIAL_IO_IOC3 7 #define UART_CLEAR_FIFO 0x01 #define UART_USE_FIFO 0x02