From afbaade3dc99838a0c39699bea175674f27322a1 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 8 Jun 2012 10:56:48 +0200 Subject: delete seven tty headers Commit 51c9d654c2def97827395a7fbfd0c6f865c26544 ("Staging: delete tty drivers") left seven headers unused: nothing in the tree includes them anymore. Two of those headers were still exported, but since nothing in the kernel actually uses the things those two headers provide, that seems pointless. Delete these seven tty headers too. Signed-off-by: Paul Bolle Cc: Arnd Bergmann Cc: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 8760be3..0a8bcb6 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -84,7 +84,6 @@ header-y += capability.h header-y += capi.h header-y += cciss_defs.h header-y += cciss_ioctl.h -header-y += cdk.h header-y += cdrom.h header-y += cgroupstats.h header-y += chio.h @@ -93,7 +92,6 @@ header-y += cn_proc.h header-y += coda.h header-y += coda_psdev.h header-y += coff.h -header-y += comstats.h header-y += connector.h header-y += const.h header-y += cramfs_fs.h diff --git a/include/linux/cd1400.h b/include/linux/cd1400.h deleted file mode 100644 index 1dc3ab0..0000000 --- a/include/linux/cd1400.h +++ /dev/null @@ -1,292 +0,0 @@ -/*****************************************************************************/ - -/* - * cd1400.h -- cd1400 UART hardware info. - * - * Copyright (C) 1996-1998 Stallion Technologies - * Copyright (C) 1994-1996 Greg Ungerer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*****************************************************************************/ -#ifndef _CD1400_H -#define _CD1400_H -/*****************************************************************************/ - -/* - * Define the number of async ports per cd1400 uart chip. - */ -#define CD1400_PORTS 4 - -/* - * Define the cd1400 uarts internal FIFO sizes. - */ -#define CD1400_TXFIFOSIZE 12 -#define CD1400_RXFIFOSIZE 12 - -/* - * Local RX FIFO thresh hold level. Also define the RTS thresh hold - * based on the RX thresh hold. - */ -#define FIFO_RXTHRESHOLD 6 -#define FIFO_RTSTHRESHOLD 7 - -/*****************************************************************************/ - -/* - * Define the cd1400 register addresses. These are all the valid - * registers with the cd1400. Some are global, some virtual, some - * per port. - */ -#define GFRCR 0x40 -#define CAR 0x68 -#define GCR 0x4b -#define SVRR 0x67 -#define RICR 0x44 -#define TICR 0x45 -#define MICR 0x46 -#define RIR 0x6b -#define TIR 0x6a -#define MIR 0x69 -#define PPR 0x7e - -#define RIVR 0x43 -#define TIVR 0x42 -#define MIVR 0x41 -#define TDR 0x63 -#define RDSR 0x62 -#define MISR 0x4c -#define EOSRR 0x60 - -#define LIVR 0x18 -#define CCR 0x05 -#define SRER 0x06 -#define COR1 0x08 -#define COR2 0x09 -#define COR3 0x0a -#define COR4 0x1e -#define COR5 0x1f -#define CCSR 0x0b -#define RDCR 0x0e -#define SCHR1 0x1a -#define SCHR2 0x1b -#define SCHR3 0x1c -#define SCHR4 0x1d -#define SCRL 0x22 -#define SCRH 0x23 -#define LNC 0x24 -#define MCOR1 0x15 -#define MCOR2 0x16 -#define RTPR 0x21 -#define MSVR1 0x6c -#define MSVR2 0x6d -#define PSVR 0x6f -#define RBPR 0x78 -#define RCOR 0x7c -#define TBPR 0x72 -#define TCOR 0x76 - -/*****************************************************************************/ - -/* - * Define the set of baud rate clock divisors. - */ -#define CD1400_CLK0 8 -#define CD1400_CLK1 32 -#define CD1400_CLK2 128 -#define CD1400_CLK3 512 -#define CD1400_CLK4 2048 - -#define CD1400_NUMCLKS 5 - -/*****************************************************************************/ - -/* - * Define the clock pre-scalar value to be a 5 ms clock. This should be - * OK for now. It would probably be better to make it 10 ms, but we - * can't fit that divisor into 8 bits! - */ -#define PPR_SCALAR 244 - -/*****************************************************************************/ - -/* - * Define values used to set character size options. - */ -#define COR1_CHL5 0x00 -#define COR1_CHL6 0x01 -#define COR1_CHL7 0x02 -#define COR1_CHL8 0x03 - -/* - * Define values used to set the number of stop bits. - */ -#define COR1_STOP1 0x00 -#define COR1_STOP15 0x04 -#define COR1_STOP2 0x08 - -/* - * Define values used to set the parity scheme in use. - */ -#define COR1_PARNONE 0x00 -#define COR1_PARFORCE 0x20 -#define COR1_PARENB 0x40 -#define COR1_PARIGNORE 0x10 - -#define COR1_PARODD 0x80 -#define COR1_PAREVEN 0x00 - -#define COR2_IXM 0x80 -#define COR2_TXIBE 0x40 -#define COR2_ETC 0x20 -#define COR2_LLM 0x10 -#define COR2_RLM 0x08 -#define COR2_RTSAO 0x04 -#define COR2_CTSAE 0x02 - -#define COR3_SCDRNG 0x80 -#define COR3_SCD34 0x40 -#define COR3_FCT 0x20 -#define COR3_SCD12 0x10 - -/* - * Define values used by COR4. - */ -#define COR4_BRKINT 0x08 -#define COR4_IGNBRK 0x18 - -/*****************************************************************************/ - -/* - * Define the modem control register values. - * Note that the actual hardware is a little different to the conventional - * pin names on the cd1400. - */ -#define MSVR1_DTR 0x01 -#define MSVR1_DSR 0x10 -#define MSVR1_RI 0x20 -#define MSVR1_CTS 0x40 -#define MSVR1_DCD 0x80 - -#define MSVR2_RTS 0x02 -#define MSVR2_DSR 0x10 -#define MSVR2_RI 0x20 -#define MSVR2_CTS 0x40 -#define MSVR2_DCD 0x80 - -#define MCOR1_DCD 0x80 -#define MCOR1_CTS 0x40 -#define MCOR1_RI 0x20 -#define MCOR1_DSR 0x10 - -#define MCOR2_DCD 0x80 -#define MCOR2_CTS 0x40 -#define MCOR2_RI 0x20 -#define MCOR2_DSR 0x10 - -/*****************************************************************************/ - -/* - * Define the bits used with the service (interrupt) enable register. - */ -#define SRER_NNDT 0x01 -#define SRER_TXEMPTY 0x02 -#define SRER_TXDATA 0x04 -#define SRER_RXDATA 0x10 -#define SRER_MODEM 0x80 - -/*****************************************************************************/ - -/* - * Define operational commands for the command register. - */ -#define CCR_RESET 0x80 -#define CCR_CORCHANGE 0x4e -#define CCR_SENDCH 0x20 -#define CCR_CHANCTRL 0x10 - -#define CCR_TXENABLE (CCR_CHANCTRL | 0x08) -#define CCR_TXDISABLE (CCR_CHANCTRL | 0x04) -#define CCR_RXENABLE (CCR_CHANCTRL | 0x02) -#define CCR_RXDISABLE (CCR_CHANCTRL | 0x01) - -#define CCR_SENDSCHR1 (CCR_SENDCH | 0x01) -#define CCR_SENDSCHR2 (CCR_SENDCH | 0x02) -#define CCR_SENDSCHR3 (CCR_SENDCH | 0x03) -#define CCR_SENDSCHR4 (CCR_SENDCH | 0x04) - -#define CCR_RESETCHAN (CCR_RESET | 0x00) -#define CCR_RESETFULL (CCR_RESET | 0x01) -#define CCR_TXFLUSHFIFO (CCR_RESET | 0x02) - -#define CCR_MAXWAIT 10000 - -/*****************************************************************************/ - -/* - * Define the valid acknowledgement types (for hw ack cycle). - */ -#define ACK_TYPMASK 0x07 -#define ACK_TYPTX 0x02 -#define ACK_TYPMDM 0x01 -#define ACK_TYPRXGOOD 0x03 -#define ACK_TYPRXBAD 0x07 - -#define SVRR_RX 0x01 -#define SVRR_TX 0x02 -#define SVRR_MDM 0x04 - -#define ST_OVERRUN 0x01 -#define ST_FRAMING 0x02 -#define ST_PARITY 0x04 -#define ST_BREAK 0x08 -#define ST_SCHAR1 0x10 -#define ST_SCHAR2 0x20 -#define ST_SCHAR3 0x30 -#define ST_SCHAR4 0x40 -#define ST_RANGE 0x70 -#define ST_SCHARMASK 0x70 -#define ST_TIMEOUT 0x80 - -#define MISR_DCD 0x80 -#define MISR_CTS 0x40 -#define MISR_RI 0x20 -#define MISR_DSR 0x10 - -/*****************************************************************************/ - -/* - * Defines for the CCSR status register. - */ -#define CCSR_RXENABLED 0x80 -#define CCSR_RXFLOWON 0x40 -#define CCSR_RXFLOWOFF 0x20 -#define CCSR_TXENABLED 0x08 -#define CCSR_TXFLOWON 0x04 -#define CCSR_TXFLOWOFF 0x02 - -/*****************************************************************************/ - -/* - * Define the embedded commands. - */ -#define ETC_CMD 0x00 -#define ETC_STARTBREAK 0x81 -#define ETC_DELAY 0x82 -#define ETC_STOPBREAK 0x83 - -/*****************************************************************************/ -#endif diff --git a/include/linux/cdk.h b/include/linux/cdk.h deleted file mode 100644 index 80093a8..0000000 --- a/include/linux/cdk.h +++ /dev/null @@ -1,486 +0,0 @@ -/*****************************************************************************/ - -/* - * cdk.h -- CDK interface definitions. - * - * Copyright (C) 1996-1998 Stallion Technologies - * Copyright (C) 1994-1996 Greg Ungerer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*****************************************************************************/ -#ifndef _CDK_H -#define _CDK_H -/*****************************************************************************/ - -#pragma pack(2) - -/* - * The following set of definitions is used to communicate with the - * shared memory interface of the Stallion intelligent multiport serial - * boards. The definitions in this file are taken directly from the - * document titled "Generic Stackable Interface, Downloader and - * Communications Development Kit". - */ - -/* - * Define the set of important shared memory addresses. These are - * required to initialize the board and get things started. All of these - * addresses are relative to the start of the shared memory. - */ -#define CDK_SIGADDR 0x200 -#define CDK_FEATADDR 0x280 -#define CDK_CDKADDR 0x300 -#define CDK_RDYADDR 0x262 - -#define CDK_ALIVEMARKER 13 - -/* - * On hardware power up the ROMs located on the EasyConnection 8/64 will - * fill out the following signature information into shared memory. This - * way the host system can quickly determine that the board is present - * and is operational. - */ -typedef struct cdkecpsig { - unsigned long magic; - unsigned short romver; - unsigned short cputype; - unsigned char panelid[8]; -} cdkecpsig_t; - -#define ECP_MAGIC 0x21504345 - -/* - * On hardware power up the ROMs located on the ONboard, Stallion and - * Brumbys will fill out the following signature information into shared - * memory. This way the host system can quickly determine that the board - * is present and is operational. - */ -typedef struct cdkonbsig { - unsigned short magic0; - unsigned short magic1; - unsigned short magic2; - unsigned short magic3; - unsigned short romver; - unsigned short memoff; - unsigned short memseg; - unsigned short amask0; - unsigned short pic; - unsigned short status; - unsigned short btype; - unsigned short clkticks; - unsigned short clkspeed; - unsigned short amask1; - unsigned short amask2; -} cdkonbsig_t; - -#define ONB_MAGIC0 0xf2a7 -#define ONB_MAGIC1 0xa149 -#define ONB_MAGIC2 0x6352 -#define ONB_MAGIC3 0xf121 - -/* - * Define the feature area structure. The feature area is the set of - * startup parameters used by the slave image when it starts executing. - * They allow for the specification of buffer sizes, debug trace, etc. - */ -typedef struct cdkfeature { - unsigned long debug; - unsigned long banner; - unsigned long etype; - unsigned long nrdevs; - unsigned long brdspec; - unsigned long txrqsize; - unsigned long rxrqsize; - unsigned long flags; -} cdkfeature_t; - -#define ETYP_DDK 0 -#define ETYP_CDK 1 - -/* - * Define the CDK header structure. This is the info that the slave - * environment sets up after it has been downloaded and started. It - * essentially provides a memory map for the shared memory interface. - */ -typedef struct cdkhdr { - unsigned short command; - unsigned short status; - unsigned short port; - unsigned short mode; - unsigned long cmd_buf[14]; - unsigned short alive_cnt; - unsigned short intrpt_mode; - unsigned char intrpt_id[8]; - unsigned char ver_release; - unsigned char ver_modification; - unsigned char ver_fix; - unsigned char deadman_restart; - unsigned short deadman; - unsigned short nrdevs; - unsigned long memp; - unsigned long hostp; - unsigned long slavep; - unsigned char hostreq; - unsigned char slavereq; - unsigned char cmd_reserved[30]; -} cdkhdr_t; - -#define MODE_DDK 0 -#define MODE_CDK 1 - -#define IMD_INTR 0x0 -#define IMD_PPINTR 0x1 -#define IMD_POLL 0xff - -/* - * Define the memory mapping structure. This structure is pointed to by - * the memp field in the stlcdkhdr struct. As many as these structures - * as required are laid out in shared memory to define how the rest of - * shared memory is divided up. There will be one for each port. - */ -typedef struct cdkmem { - unsigned short dtype; - unsigned long offset; -} cdkmem_t; - -#define TYP_UNDEFINED 0x0 -#define TYP_ASYNCTRL 0x1 -#define TYP_ASYNC 0x20 -#define TYP_PARALLEL 0x40 -#define TYP_SYNCX21 0x60 - -/*****************************************************************************/ - -/* - * Following is a set of defines and structures used to actually deal - * with the serial ports on the board. Firstly is the set of commands - * that can be applied to ports. - */ -#define ASYCMD (((unsigned long) 'a') << 8) - -#define A_NULL (ASYCMD | 0) -#define A_FLUSH (ASYCMD | 1) -#define A_BREAK (ASYCMD | 2) -#define A_GETPORT (ASYCMD | 3) -#define A_SETPORT (ASYCMD | 4) -#define A_SETPORTF (ASYCMD | 5) -#define A_SETPORTFTX (ASYCMD | 6) -#define A_SETPORTFRX (ASYCMD | 7) -#define A_GETSIGNALS (ASYCMD | 8) -#define A_SETSIGNALS (ASYCMD | 9) -#define A_SETSIGNALSF (ASYCMD | 10) -#define A_SETSIGNALSFTX (ASYCMD | 11) -#define A_SETSIGNALSFRX (ASYCMD | 12) -#define A_GETNOTIFY (ASYCMD | 13) -#define A_SETNOTIFY (ASYCMD | 14) -#define A_NOTIFY (ASYCMD | 15) -#define A_PORTCTRL (ASYCMD | 16) -#define A_GETSTATS (ASYCMD | 17) -#define A_RQSTATE (ASYCMD | 18) -#define A_FLOWSTATE (ASYCMD | 19) -#define A_CLEARSTATS (ASYCMD | 20) - -/* - * Define those arguments used for simple commands. - */ -#define FLUSHRX 0x1 -#define FLUSHTX 0x2 - -#define BREAKON -1 -#define BREAKOFF -2 - -/* - * Define the port setting structure, and all those defines that go along - * with it. Basically this structure defines the characteristics of this - * port: baud rate, chars, parity, input/output char cooking etc. - */ -typedef struct asyport { - unsigned long baudout; - unsigned long baudin; - unsigned long iflag; - unsigned long oflag; - unsigned long lflag; - unsigned long pflag; - unsigned long flow; - unsigned long spare1; - unsigned short vtime; - unsigned short vmin; - unsigned short txlo; - unsigned short txhi; - unsigned short rxlo; - unsigned short rxhi; - unsigned short rxhog; - unsigned short spare2; - unsigned char csize; - unsigned char stopbs; - unsigned char parity; - unsigned char stopin; - unsigned char startin; - unsigned char stopout; - unsigned char startout; - unsigned char parmark; - unsigned char brkmark; - unsigned char cc[11]; -} asyport_t; - -#define PT_STOP1 0x0 -#define PT_STOP15 0x1 -#define PT_STOP2 0x2 - -#define PT_NOPARITY 0x0 -#define PT_ODDPARITY 0x1 -#define PT_EVENPARITY 0x2 -#define PT_MARKPARITY 0x3 -#define PT_SPACEPARITY 0x4 - -#define F_NONE 0x0 -#define F_IXON 0x1 -#define F_IXOFF 0x2 -#define F_IXANY 0x4 -#define F_IOXANY 0x8 -#define F_RTSFLOW 0x10 -#define F_CTSFLOW 0x20 -#define F_DTRFLOW 0x40 -#define F_DCDFLOW 0x80 -#define F_DSROFLOW 0x100 -#define F_DSRIFLOW 0x200 - -#define FI_NORX 0x1 -#define FI_RAW 0x2 -#define FI_ISTRIP 0x4 -#define FI_UCLC 0x8 -#define FI_INLCR 0x10 -#define FI_ICRNL 0x20 -#define FI_IGNCR 0x40 -#define FI_IGNBREAK 0x80 -#define FI_DSCRDBREAK 0x100 -#define FI_1MARKBREAK 0x200 -#define FI_2MARKBREAK 0x400 -#define FI_XCHNGBREAK 0x800 -#define FI_IGNRXERRS 0x1000 -#define FI_DSCDRXERRS 0x2000 -#define FI_1MARKRXERRS 0x4000 -#define FI_2MARKRXERRS 0x8000 -#define FI_XCHNGRXERRS 0x10000 -#define FI_DSCRDNULL 0x20000 - -#define FO_OLCUC 0x1 -#define FO_ONLCR 0x2 -#define FO_OOCRNL 0x4 -#define FO_ONOCR 0x8 -#define FO_ONLRET 0x10 -#define FO_ONL 0x20 -#define FO_OBS 0x40 -#define FO_OVT 0x80 -#define FO_OFF 0x100 -#define FO_OTAB1 0x200 -#define FO_OTAB2 0x400 -#define FO_OTAB3 0x800 -#define FO_OCR1 0x1000 -#define FO_OCR2 0x2000 -#define FO_OCR3 0x4000 -#define FO_OFILL 0x8000 -#define FO_ODELL 0x10000 - -#define P_RTSLOCK 0x1 -#define P_CTSLOCK 0x2 -#define P_MAPRTS 0x4 -#define P_MAPCTS 0x8 -#define P_LOOPBACK 0x10 -#define P_DTRFOLLOW 0x20 -#define P_FAKEDCD 0x40 - -#define P_RXIMIN 0x10000 -#define P_RXITIME 0x20000 -#define P_RXTHOLD 0x40000 - -/* - * Define a structure to communicate serial port signal and data state - * information. - */ -typedef struct asysigs { - unsigned long data; - unsigned long signal; - unsigned long sigvalue; -} asysigs_t; - -#define DT_TXBUSY 0x1 -#define DT_TXEMPTY 0x2 -#define DT_TXLOW 0x4 -#define DT_TXHIGH 0x8 -#define DT_TXFULL 0x10 -#define DT_TXHOG 0x20 -#define DT_TXFLOWED 0x40 -#define DT_TXBREAK 0x80 - -#define DT_RXBUSY 0x100 -#define DT_RXEMPTY 0x200 -#define DT_RXLOW 0x400 -#define DT_RXHIGH 0x800 -#define DT_RXFULL 0x1000 -#define DT_RXHOG 0x2000 -#define DT_RXFLOWED 0x4000 -#define DT_RXBREAK 0x8000 - -#define SG_DTR 0x1 -#define SG_DCD 0x2 -#define SG_RTS 0x4 -#define SG_CTS 0x8 -#define SG_DSR 0x10 -#define SG_RI 0x20 - -/* - * Define the notification setting structure. This is used to tell the - * port what events we want to be informed about. Fields here use the - * same defines as for the asysigs structure above. - */ -typedef struct asynotify { - unsigned long ctrl; - unsigned long data; - unsigned long signal; - unsigned long sigvalue; -} asynotify_t; - -/* - * Define the port control structure. It is used to do fine grain - * control operations on the port. - */ -typedef struct { - unsigned long rxctrl; - unsigned long txctrl; - char rximdch; - char tximdch; - char spare1; - char spare2; -} asyctrl_t; - -#define CT_ENABLE 0x1 -#define CT_DISABLE 0x2 -#define CT_STOP 0x4 -#define CT_START 0x8 -#define CT_STARTFLOW 0x10 -#define CT_STOPFLOW 0x20 -#define CT_SENDCHR 0x40 - -/* - * Define the stats structure kept for each port. This is a useful set - * of data collected for each port on the slave. The A_GETSTATS command - * is used to retrieve this data from the slave. - */ -typedef struct asystats { - unsigned long opens; - unsigned long txchars; - unsigned long rxchars; - unsigned long txringq; - unsigned long rxringq; - unsigned long txmsgs; - unsigned long rxmsgs; - unsigned long txflushes; - unsigned long rxflushes; - unsigned long overruns; - unsigned long framing; - unsigned long parity; - unsigned long ringover; - unsigned long lost; - unsigned long rxstart; - unsigned long rxstop; - unsigned long txstart; - unsigned long txstop; - unsigned long dcdcnt; - unsigned long dtrcnt; - unsigned long ctscnt; - unsigned long rtscnt; - unsigned long dsrcnt; - unsigned long ricnt; - unsigned long txbreaks; - unsigned long rxbreaks; - unsigned long signals; - unsigned long state; - unsigned long hwid; -} asystats_t; - -/*****************************************************************************/ - -/* - * All command and control communication with a device on the slave is - * via a control block in shared memory. Each device has its own control - * block, defined by the following structure. The control block allows - * the host to open, close and control the device on the slave. - */ -typedef struct cdkctrl { - unsigned char open; - unsigned char close; - unsigned long openarg; - unsigned long closearg; - unsigned long cmd; - unsigned long status; - unsigned long args[32]; -} cdkctrl_t; - -/* - * Each device on the slave passes data to and from the host via a ring - * queue in shared memory. Define a ring queue structure to hold the - * vital information about each ring queue. Two ring queues will be - * allocated for each port, one for receive data and one for transmit - * data. - */ -typedef struct cdkasyrq { - unsigned long offset; - unsigned short size; - unsigned short head; - unsigned short tail; -} cdkasyrq_t; - -/* - * Each asynchronous port is defined in shared memory by the following - * structure. It contains a control block to command a device, and also - * the necessary data channel information as well. - */ -typedef struct cdkasy { - cdkctrl_t ctrl; - unsigned short notify; - asynotify_t changed; - unsigned short receive; - cdkasyrq_t rxq; - unsigned short transmit; - cdkasyrq_t txq; -} cdkasy_t; - -#pragma pack() - -/*****************************************************************************/ - -/* - * Define the set of ioctls used by the driver to do special things - * to the board. These include interrupting it, and initializing - * the driver after board startup and shutdown. - */ -#include - -#define STL_BINTR _IO('s',20) -#define STL_BSTART _IO('s',21) -#define STL_BSTOP _IO('s',22) -#define STL_BRESET _IO('s',23) - -/* - * Define a set of ioctl extensions, used to get at special stuff. - */ -#define STL_GETPFLAG _IO('s',80) -#define STL_SETPFLAG _IO('s',81) - -/*****************************************************************************/ -#endif diff --git a/include/linux/comstats.h b/include/linux/comstats.h deleted file mode 100644 index 3f5ea8e..0000000 --- a/include/linux/comstats.h +++ /dev/null @@ -1,119 +0,0 @@ -/*****************************************************************************/ - -/* - * comstats.h -- Serial Port Stats. - * - * Copyright (C) 1996-1998 Stallion Technologies - * Copyright (C) 1994-1996 Greg Ungerer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*****************************************************************************/ -#ifndef _COMSTATS_H -#define _COMSTATS_H -/*****************************************************************************/ - -/* - * Serial port stats structure. The structure itself is UART - * independent, but some fields may be UART/driver specific (for - * example state). - */ - -typedef struct { - unsigned long brd; - unsigned long panel; - unsigned long port; - unsigned long hwid; - unsigned long type; - unsigned long txtotal; - unsigned long rxtotal; - unsigned long txbuffered; - unsigned long rxbuffered; - unsigned long rxoverrun; - unsigned long rxparity; - unsigned long rxframing; - unsigned long rxlost; - unsigned long txbreaks; - unsigned long rxbreaks; - unsigned long txxon; - unsigned long txxoff; - unsigned long rxxon; - unsigned long rxxoff; - unsigned long txctson; - unsigned long txctsoff; - unsigned long rxrtson; - unsigned long rxrtsoff; - unsigned long modem; - unsigned long state; - unsigned long flags; - unsigned long ttystate; - unsigned long cflags; - unsigned long iflags; - unsigned long oflags; - unsigned long lflags; - unsigned long signals; -} comstats_t; - - -/* - * Board stats structure. Returns useful info about the board. - */ - -#define COM_MAXPANELS 8 - -typedef struct { - unsigned long panel; - unsigned long type; - unsigned long hwid; - unsigned long nrports; -} companel_t; - -typedef struct { - unsigned long brd; - unsigned long type; - unsigned long hwid; - unsigned long state; - unsigned long ioaddr; - unsigned long ioaddr2; - unsigned long memaddr; - unsigned long irq; - unsigned long nrpanels; - unsigned long nrports; - companel_t panels[COM_MAXPANELS]; -} combrd_t; - - -/* - * Define the ioctl operations for stats stuff. - */ -#include - -#define COM_GETPORTSTATS _IO('c',30) -#define COM_CLRPORTSTATS _IO('c',31) -#define COM_GETBRDSTATS _IO('c',32) - - -/* - * Define the set of ioctls that give user level access to the - * private port, panel and board structures. The argument required - * will be driver dependent! - */ -#define COM_READPORT _IO('c',40) -#define COM_READBOARD _IO('c',41) -#define COM_READPANEL _IO('c',42) - -/*****************************************************************************/ -#endif diff --git a/include/linux/istallion.h b/include/linux/istallion.h deleted file mode 100644 index ad700a6..0000000 --- a/include/linux/istallion.h +++ /dev/null @@ -1,123 +0,0 @@ -/*****************************************************************************/ - -/* - * istallion.h -- stallion intelligent multiport serial driver. - * - * Copyright (C) 1996-1998 Stallion Technologies - * Copyright (C) 1994-1996 Greg Ungerer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*****************************************************************************/ -#ifndef _ISTALLION_H -#define _ISTALLION_H -/*****************************************************************************/ - -/* - * Define important driver constants here. - */ -#define STL_MAXBRDS 4 -#define STL_MAXPANELS 4 -#define STL_MAXPORTS 64 -#define STL_MAXCHANS (STL_MAXPORTS + 1) -#define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS) - - -/* - * Define a set of structures to hold all the board/panel/port info - * for our ports. These will be dynamically allocated as required at - * driver initialization time. - */ - -/* - * Port and board structures to hold status info about each object. - * The board structure contains pointers to structures for each port - * connected to it. Panels are not distinguished here, since - * communication with the slave board will always be on a per port - * basis. - */ -struct stliport { - unsigned long magic; - struct tty_port port; - unsigned int portnr; - unsigned int panelnr; - unsigned int brdnr; - unsigned long state; - unsigned int devnr; - int baud_base; - int custom_divisor; - int closing_wait; - int rc; - int argsize; - void *argp; - unsigned int rxmarkmsk; - wait_queue_head_t raw_wait; - struct asysigs asig; - unsigned long addr; - unsigned long rxoffset; - unsigned long txoffset; - unsigned long sigs; - unsigned long pflag; - unsigned int rxsize; - unsigned int txsize; - unsigned char reqbit; - unsigned char portidx; - unsigned char portbit; -}; - -/* - * Use a structure of function pointers to do board level operations. - * These include, enable/disable, paging shared memory, interrupting, etc. - */ -struct stlibrd { - unsigned long magic; - unsigned int brdnr; - unsigned int brdtype; - unsigned long state; - unsigned int nrpanels; - unsigned int nrports; - unsigned int nrdevs; - unsigned int iobase; - int iosize; - unsigned long memaddr; - void __iomem *membase; - unsigned long memsize; - int pagesize; - int hostoffset; - int slaveoffset; - int bitsize; - int enabval; - unsigned int panels[STL_MAXPANELS]; - int panelids[STL_MAXPANELS]; - void (*init)(struct stlibrd *brdp); - void (*enable)(struct stlibrd *brdp); - void (*reenable)(struct stlibrd *brdp); - void (*disable)(struct stlibrd *brdp); - void __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line); - void (*intr)(struct stlibrd *brdp); - void (*reset)(struct stlibrd *brdp); - struct stliport *ports[STL_MAXPORTS]; -}; - - -/* - * Define MAGIC numbers used for above structures. - */ -#define STLI_PORTMAGIC 0xe671c7a1 -#define STLI_BOARDMAGIC 0x4bc6c825 - -/*****************************************************************************/ -#endif diff --git a/include/linux/sc26198.h b/include/linux/sc26198.h deleted file mode 100644 index 7ca35ab..0000000 --- a/include/linux/sc26198.h +++ /dev/null @@ -1,533 +0,0 @@ -/*****************************************************************************/ - -/* - * sc26198.h -- SC26198 UART hardware info. - * - * Copyright (C) 1995-1998 Stallion Technologies - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*****************************************************************************/ -#ifndef _SC26198_H -#define _SC26198_H -/*****************************************************************************/ - -/* - * Define the number of async ports per sc26198 uart device. - */ -#define SC26198_PORTS 8 - -/* - * Baud rate timing clocks. All derived from a master 14.7456 MHz clock. - */ -#define SC26198_MASTERCLOCK 14745600L -#define SC26198_DCLK (SC26198_MASTERCLOCK) -#define SC26198_CCLK (SC26198_MASTERCLOCK / 2) -#define SC26198_BCLK (SC26198_MASTERCLOCK / 4) - -/* - * Define internal FIFO sizes for the 26198 ports. - */ -#define SC26198_TXFIFOSIZE 16 -#define SC26198_RXFIFOSIZE 16 - -/*****************************************************************************/ - -/* - * Global register definitions. These registers are global to each 26198 - * device, not specific ports on it. - */ -#define TSTR 0x0d -#define GCCR 0x0f -#define ICR 0x1b -#define WDTRCR 0x1d -#define IVR 0x1f -#define BRGTRUA 0x84 -#define GPOSR 0x87 -#define GPOC 0x8b -#define UCIR 0x8c -#define CIR 0x8c -#define BRGTRUB 0x8d -#define GRXFIFO 0x8e -#define GTXFIFO 0x8e -#define GCCR2 0x8f -#define BRGTRLA 0x94 -#define GPOR 0x97 -#define GPOD 0x9b -#define BRGTCR 0x9c -#define GICR 0x9c -#define BRGTRLB 0x9d -#define GIBCR 0x9d -#define GITR 0x9f - -/* - * Per port channel registers. These are the register offsets within - * the port address space, so need to have the port address (0 to 7) - * inserted in bit positions 4:6. - */ -#define MR0 0x00 -#define MR1 0x01 -#define IOPCR 0x02 -#define BCRBRK 0x03 -#define BCRCOS 0x04 -#define BCRX 0x06 -#define BCRA 0x07 -#define XONCR 0x08 -#define XOFFCR 0x09 -#define ARCR 0x0a -#define RXCSR 0x0c -#define TXCSR 0x0e -#define MR2 0x80 -#define SR 0x81 -#define SCCR 0x81 -#define ISR 0x82 -#define IMR 0x82 -#define TXFIFO 0x83 -#define RXFIFO 0x83 -#define IPR 0x84 -#define IOPIOR 0x85 -#define XISR 0x86 - -/* - * For any given port calculate the address to use to access a specified - * register. This is only used for unusual access, mostly this is done - * through the assembler access routines. - */ -#define SC26198_PORTREG(port,reg) ((((port) & 0x07) << 4) | (reg)) - -/*****************************************************************************/ - -/* - * Global configuration control register bit definitions. - */ -#define GCCR_NOACK 0x00 -#define GCCR_IVRACK 0x02 -#define GCCR_IVRCHANACK 0x04 -#define GCCR_IVRTYPCHANACK 0x06 -#define GCCR_ASYNCCYCLE 0x00 -#define GCCR_SYNCCYCLE 0x40 - -/*****************************************************************************/ - -/* - * Mode register 0 bit definitions. - */ -#define MR0_ADDRNONE 0x00 -#define MR0_AUTOWAKE 0x01 -#define MR0_AUTODOZE 0x02 -#define MR0_AUTOWAKEDOZE 0x03 -#define MR0_SWFNONE 0x00 -#define MR0_SWFTX 0x04 -#define MR0_SWFRX 0x08 -#define MR0_SWFRXTX 0x0c -#define MR0_TXMASK 0x30 -#define MR0_TXEMPTY 0x00 -#define MR0_TXHIGH 0x10 -#define MR0_TXHALF 0x20 -#define MR0_TXRDY 0x00 -#define MR0_ADDRNT 0x00 -#define MR0_ADDRT 0x40 -#define MR0_SWFNT 0x00 -#define MR0_SWFT 0x80 - -/* - * Mode register 1 bit definitions. - */ -#define MR1_CS5 0x00 -#define MR1_CS6 0x01 -#define MR1_CS7 0x02 -#define MR1_CS8 0x03 -#define MR1_PAREVEN 0x00 -#define MR1_PARODD 0x04 -#define MR1_PARENB 0x00 -#define MR1_PARFORCE 0x08 -#define MR1_PARNONE 0x10 -#define MR1_PARSPECIAL 0x18 -#define MR1_ERRCHAR 0x00 -#define MR1_ERRBLOCK 0x20 -#define MR1_ISRUNMASKED 0x00 -#define MR1_ISRMASKED 0x40 -#define MR1_AUTORTS 0x80 - -/* - * Mode register 2 bit definitions. - */ -#define MR2_STOP1 0x00 -#define MR2_STOP15 0x01 -#define MR2_STOP2 0x02 -#define MR2_STOP916 0x03 -#define MR2_RXFIFORDY 0x00 -#define MR2_RXFIFOHALF 0x04 -#define MR2_RXFIFOHIGH 0x08 -#define MR2_RXFIFOFULL 0x0c -#define MR2_AUTOCTS 0x10 -#define MR2_TXRTS 0x20 -#define MR2_MODENORM 0x00 -#define MR2_MODEAUTOECHO 0x40 -#define MR2_MODELOOP 0x80 -#define MR2_MODEREMECHO 0xc0 - -/*****************************************************************************/ - -/* - * Baud Rate Generator (BRG) selector values. - */ -#define BRG_50 0x00 -#define BRG_75 0x01 -#define BRG_150 0x02 -#define BRG_200 0x03 -#define BRG_300 0x04 -#define BRG_450 0x05 -#define BRG_600 0x06 -#define BRG_900 0x07 -#define BRG_1200 0x08 -#define BRG_1800 0x09 -#define BRG_2400 0x0a -#define BRG_3600 0x0b -#define BRG_4800 0x0c -#define BRG_7200 0x0d -#define BRG_9600 0x0e -#define BRG_14400 0x0f -#define BRG_19200 0x10 -#define BRG_28200 0x11 -#define BRG_38400 0x12 -#define BRG_57600 0x13 -#define BRG_115200 0x14 -#define BRG_230400 0x15 -#define BRG_GIN0 0x16 -#define BRG_GIN1 0x17 -#define BRG_CT0 0x18 -#define BRG_CT1 0x19 -#define BRG_RX2TX316 0x1b -#define BRG_RX2TX31 0x1c - -#define SC26198_MAXBAUD 921600 - -/*****************************************************************************/ - -/* - * Command register command definitions. - */ -#define CR_NULL 0x04 -#define CR_ADDRNORMAL 0x0c -#define CR_RXRESET 0x14 -#define CR_TXRESET 0x1c -#define CR_CLEARRXERR 0x24 -#define CR_BREAKRESET 0x2c -#define CR_TXSTARTBREAK 0x34 -#define CR_TXSTOPBREAK 0x3c -#define CR_RTSON 0x44 -#define CR_RTSOFF 0x4c -#define CR_ADDRINIT 0x5c -#define CR_RXERRBLOCK 0x6c -#define CR_TXSENDXON 0x84 -#define CR_TXSENDXOFF 0x8c -#define CR_GANGXONSET 0x94 -#define CR_GANGXOFFSET 0x9c -#define CR_GANGXONINIT 0xa4 -#define CR_GANGXOFFINIT 0xac -#define CR_HOSTXON 0xb4 -#define CR_HOSTXOFF 0xbc -#define CR_CANCELXOFF 0xc4 -#define CR_ADDRRESET 0xdc -#define CR_RESETALLPORTS 0xf4 -#define CR_RESETALL 0xfc - -#define CR_RXENABLE 0x01 -#define CR_TXENABLE 0x02 - -/*****************************************************************************/ - -/* - * Channel status register. - */ -#define SR_RXRDY 0x01 -#define SR_RXFULL 0x02 -#define SR_TXRDY 0x04 -#define SR_TXEMPTY 0x08 -#define SR_RXOVERRUN 0x10 -#define SR_RXPARITY 0x20 -#define SR_RXFRAMING 0x40 -#define SR_RXBREAK 0x80 - -#define SR_RXERRS (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN) - -/*****************************************************************************/ - -/* - * Interrupt status register and interrupt mask register bit definitions. - */ -#define IR_TXRDY 0x01 -#define IR_RXRDY 0x02 -#define IR_RXBREAK 0x04 -#define IR_XONXOFF 0x10 -#define IR_ADDRRECOG 0x20 -#define IR_RXWATCHDOG 0x40 -#define IR_IOPORT 0x80 - -/*****************************************************************************/ - -/* - * Interrupt vector register field definitions. - */ -#define IVR_CHANMASK 0x07 -#define IVR_TYPEMASK 0x18 -#define IVR_CONSTMASK 0xc0 - -#define IVR_RXDATA 0x10 -#define IVR_RXBADDATA 0x18 -#define IVR_TXDATA 0x08 -#define IVR_OTHER 0x00 - -/*****************************************************************************/ - -/* - * BRG timer control register bit definitions. - */ -#define BRGCTCR_DISABCLK0 0x00 -#define BRGCTCR_ENABCLK0 0x08 -#define BRGCTCR_DISABCLK1 0x00 -#define BRGCTCR_ENABCLK1 0x80 - -#define BRGCTCR_0SCLK16 0x00 -#define BRGCTCR_0SCLK32 0x01 -#define BRGCTCR_0SCLK64 0x02 -#define BRGCTCR_0SCLK128 0x03 -#define BRGCTCR_0X1 0x04 -#define BRGCTCR_0X12 0x05 -#define BRGCTCR_0IO1A 0x06 -#define BRGCTCR_0GIN0 0x07 - -#define BRGCTCR_1SCLK16 0x00 -#define BRGCTCR_1SCLK32 0x10 -#define BRGCTCR_1SCLK64 0x20 -#define BRGCTCR_1SCLK128 0x30 -#define BRGCTCR_1X1 0x40 -#define BRGCTCR_1X12 0x50 -#define BRGCTCR_1IO1B 0x60 -#define BRGCTCR_1GIN1 0x70 - -/*****************************************************************************/ - -/* - * Watch dog timer enable register. - */ -#define WDTRCR_ENABALL 0xff - -/*****************************************************************************/ - -/* - * XON/XOFF interrupt status register. - */ -#define XISR_TXCHARMASK 0x03 -#define XISR_TXCHARNORMAL 0x00 -#define XISR_TXWAIT 0x01 -#define XISR_TXXOFFPEND 0x02 -#define XISR_TXXONPEND 0x03 - -#define XISR_TXFLOWMASK 0x0c -#define XISR_TXNORMAL 0x00 -#define XISR_TXSTOPPEND 0x04 -#define XISR_TXSTARTED 0x08 -#define XISR_TXSTOPPED 0x0c - -#define XISR_RXFLOWMASK 0x30 -#define XISR_RXFLOWNONE 0x00 -#define XISR_RXXONSENT 0x10 -#define XISR_RXXOFFSENT 0x20 - -#define XISR_RXXONGOT 0x40 -#define XISR_RXXOFFGOT 0x80 - -/*****************************************************************************/ - -/* - * Current interrupt register. - */ -#define CIR_TYPEMASK 0xc0 -#define CIR_TYPEOTHER 0x00 -#define CIR_TYPETX 0x40 -#define CIR_TYPERXGOOD 0x80 -#define CIR_TYPERXBAD 0xc0 - -#define CIR_RXDATA 0x80 -#define CIR_RXBADDATA 0x40 -#define CIR_TXDATA 0x40 - -#define CIR_CHANMASK 0x07 -#define CIR_CNTMASK 0x38 - -#define CIR_SUBTYPEMASK 0x38 -#define CIR_SUBNONE 0x00 -#define CIR_SUBCOS 0x08 -#define CIR_SUBADDR 0x10 -#define CIR_SUBXONXOFF 0x18 -#define CIR_SUBBREAK 0x28 - -/*****************************************************************************/ - -/* - * Global interrupting channel register. - */ -#define GICR_CHANMASK 0x07 - -/*****************************************************************************/ - -/* - * Global interrupting byte count register. - */ -#define GICR_COUNTMASK 0x0f - -/*****************************************************************************/ - -/* - * Global interrupting type register. - */ -#define GITR_RXMASK 0xc0 -#define GITR_RXNONE 0x00 -#define GITR_RXBADDATA 0x80 -#define GITR_RXGOODDATA 0xc0 -#define GITR_TXDATA 0x20 - -#define GITR_SUBTYPEMASK 0x07 -#define GITR_SUBNONE 0x00 -#define GITR_SUBCOS 0x01 -#define GITR_SUBADDR 0x02 -#define GITR_SUBXONXOFF 0x03 -#define GITR_SUBBREAK 0x05 - -/*****************************************************************************/ - -/* - * Input port change register. - */ -#define IPR_CTS 0x01 -#define IPR_DTR 0x02 -#define IPR_RTS 0x04 -#define IPR_DCD 0x08 -#define IPR_CTSCHANGE 0x10 -#define IPR_DTRCHANGE 0x20 -#define IPR_RTSCHANGE 0x40 -#define IPR_DCDCHANGE 0x80 - -#define IPR_CHANGEMASK 0xf0 - -/*****************************************************************************/ - -/* - * IO port interrupt and output register. - */ -#define IOPR_CTS 0x01 -#define IOPR_DTR 0x02 -#define IOPR_RTS 0x04 -#define IOPR_DCD 0x08 -#define IOPR_CTSCOS 0x10 -#define IOPR_DTRCOS 0x20 -#define IOPR_RTSCOS 0x40 -#define IOPR_DCDCOS 0x80 - -/*****************************************************************************/ - -/* - * IO port configuration register. - */ -#define IOPCR_SETCTS 0x00 -#define IOPCR_SETDTR 0x04 -#define IOPCR_SETRTS 0x10 -#define IOPCR_SETDCD 0x00 - -#define IOPCR_SETSIGS (IOPCR_SETRTS | IOPCR_SETRTS | IOPCR_SETDTR | IOPCR_SETDCD) - -/*****************************************************************************/ - -/* - * General purpose output select register. - */ -#define GPORS_TXC1XA 0x08 -#define GPORS_TXC16XA 0x09 -#define GPORS_RXC16XA 0x0a -#define GPORS_TXC16XB 0x0b -#define GPORS_GPOR3 0x0c -#define GPORS_GPOR2 0x0d -#define GPORS_GPOR1 0x0e -#define GPORS_GPOR0 0x0f - -/*****************************************************************************/ - -/* - * General purpose output register. - */ -#define GPOR_0 0x01 -#define GPOR_1 0x02 -#define GPOR_2 0x04 -#define GPOR_3 0x08 - -/*****************************************************************************/ - -/* - * General purpose output clock register. - */ -#define GPORC_0NONE 0x00 -#define GPORC_0GIN0 0x01 -#define GPORC_0GIN1 0x02 -#define GPORC_0IO3A 0x02 - -#define GPORC_1NONE 0x00 -#define GPORC_1GIN0 0x04 -#define GPORC_1GIN1 0x08 -#define GPORC_1IO3C 0x0c - -#define GPORC_2NONE 0x00 -#define GPORC_2GIN0 0x10 -#define GPORC_2GIN1 0x20 -#define GPORC_2IO3E 0x20 - -#define GPORC_3NONE 0x00 -#define GPORC_3GIN0 0x40 -#define GPORC_3GIN1 0x80 -#define GPORC_3IO3G 0xc0 - -/*****************************************************************************/ - -/* - * General purpose output data register. - */ -#define GPOD_0MASK 0x03 -#define GPOD_0SET1 0x00 -#define GPOD_0SET0 0x01 -#define GPOD_0SETR0 0x02 -#define GPOD_0SETIO3B 0x03 - -#define GPOD_1MASK 0x0c -#define GPOD_1SET1 0x00 -#define GPOD_1SET0 0x04 -#define GPOD_1SETR0 0x08 -#define GPOD_1SETIO3D 0x0c - -#define GPOD_2MASK 0x30 -#define GPOD_2SET1 0x00 -#define GPOD_2SET0 0x10 -#define GPOD_2SETR0 0x20 -#define GPOD_2SETIO3F 0x30 - -#define GPOD_3MASK 0xc0 -#define GPOD_3SET1 0x00 -#define GPOD_3SET0 0x40 -#define GPOD_3SETR0 0x80 -#define GPOD_3SETIO3H 0xc0 - -/*****************************************************************************/ -#endif diff --git a/include/linux/serial167.h b/include/linux/serial167.h deleted file mode 100644 index 59c81b7..0000000 --- a/include/linux/serial167.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * serial167.h - * - * Richard Hirst [richard@sleepie.demon.co.uk] - * - * Based on cyclades.h - */ - -struct cyclades_monitor { - unsigned long int_count; - unsigned long char_count; - unsigned long char_max; - unsigned long char_last; -}; - -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct cyclades_port { - int magic; - int type; - int card; - int line; - int flags; /* defined in tty.h */ - struct tty_struct *tty; - int read_status_mask; - int timeout; - int xmit_fifo_size; - int cor1,cor2,cor3,cor4,cor5,cor6,cor7; - int tbpr,tco,rbpr,rco; - int ignore_status_mask; - int close_delay; - int IER; /* Interrupt Enable Register */ - unsigned long last_active; - int count; /* # of fd on device */ - int x_char; /* to be pushed out ASAP */ - int x_break; - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - int default_threshold; - int default_timeout; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - struct cyclades_monitor mon; -}; - -#define CYCLADES_MAGIC 0x4359 - -#define CYGETMON 0x435901 -#define CYGETTHRESH 0x435902 -#define CYSETTHRESH 0x435903 -#define CYGETDEFTHRESH 0x435904 -#define CYSETDEFTHRESH 0x435905 -#define CYGETTIMEOUT 0x435906 -#define CYSETTIMEOUT 0x435907 -#define CYGETDEFTIMEOUT 0x435908 -#define CYSETDEFTIMEOUT 0x435909 - -#define CyMaxChipsPerCard 1 - -/**** cd2401 registers ****/ - -#define CyGFRCR (0x81) -#define CyCCR (0x13) -#define CyCLR_CHAN (0x40) -#define CyINIT_CHAN (0x20) -#define CyCHIP_RESET (0x10) -#define CyENB_XMTR (0x08) -#define CyDIS_XMTR (0x04) -#define CyENB_RCVR (0x02) -#define CyDIS_RCVR (0x01) -#define CyCAR (0xee) -#define CyIER (0x11) -#define CyMdmCh (0x80) -#define CyRxExc (0x20) -#define CyRxData (0x08) -#define CyTxMpty (0x02) -#define CyTxRdy (0x01) -#define CyLICR (0x26) -#define CyRISR (0x89) -#define CyTIMEOUT (0x80) -#define CySPECHAR (0x70) -#define CyOVERRUN (0x08) -#define CyPARITY (0x04) -#define CyFRAME (0x02) -#define CyBREAK (0x01) -#define CyREOIR (0x84) -#define CyTEOIR (0x85) -#define CyMEOIR (0x86) -#define CyNOTRANS (0x08) -#define CyRFOC (0x30) -#define CyRDR (0xf8) -#define CyTDR (0xf8) -#define CyMISR (0x8b) -#define CyRISR (0x89) -#define CyTISR (0x8a) -#define CyMSVR1 (0xde) -#define CyMSVR2 (0xdf) -#define CyDSR (0x80) -#define CyDCD (0x40) -#define CyCTS (0x20) -#define CyDTR (0x02) -#define CyRTS (0x01) -#define CyRTPRL (0x25) -#define CyRTPRH (0x24) -#define CyCOR1 (0x10) -#define CyPARITY_NONE (0x00) -#define CyPARITY_E (0x40) -#define CyPARITY_O (0xC0) -#define Cy_5_BITS (0x04) -#define Cy_6_BITS (0x05) -#define Cy_7_BITS (0x06) -#define Cy_8_BITS (0x07) -#define CyCOR2 (0x17) -#define CyETC (0x20) -#define CyCtsAE (0x02) -#define CyCOR3 (0x16) -#define Cy_1_STOP (0x02) -#define Cy_2_STOP (0x04) -#define CyCOR4 (0x15) -#define CyREC_FIFO (0x0F) /* Receive FIFO threshold */ -#define CyCOR5 (0x14) -#define CyCOR6 (0x18) -#define CyCOR7 (0x07) -#define CyRBPR (0xcb) -#define CyRCOR (0xc8) -#define CyTBPR (0xc3) -#define CyTCOR (0xc0) -#define CySCHR1 (0x1f) -#define CySCHR2 (0x1e) -#define CyTPR (0xda) -#define CyPILR1 (0xe3) -#define CyPILR2 (0xe0) -#define CyPILR3 (0xe1) -#define CyCMR (0x1b) -#define CyASYNC (0x02) -#define CyLICR (0x26) -#define CyLIVR (0x09) -#define CySCRL (0x23) -#define CySCRH (0x22) -#define CyTFTC (0x80) - - -/* max number of chars in the FIFO */ - -#define CyMAX_CHAR_FIFO 12 - -/***************************************************************************/ diff --git a/include/linux/stallion.h b/include/linux/stallion.h deleted file mode 100644 index 336af33c..0000000 --- a/include/linux/stallion.h +++ /dev/null @@ -1,147 +0,0 @@ -/*****************************************************************************/ - -/* - * stallion.h -- stallion multiport serial driver. - * - * Copyright (C) 1996-1998 Stallion Technologies - * Copyright (C) 1994-1996 Greg Ungerer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/*****************************************************************************/ -#ifndef _STALLION_H -#define _STALLION_H -/*****************************************************************************/ - -/* - * Define important driver constants here. - */ -#define STL_MAXBRDS 4 -#define STL_MAXPANELS 4 -#define STL_MAXBANKS 8 -#define STL_PORTSPERPANEL 16 -#define STL_MAXPORTS 64 -#define STL_MAXDEVS (STL_MAXBRDS * STL_MAXPORTS) - - -/* - * Define a set of structures to hold all the board/panel/port info - * for our ports. These will be dynamically allocated as required. - */ - -/* - * Define a ring queue structure for each port. This will hold the - * TX data waiting to be output. Characters are fed into this buffer - * from the line discipline (or even direct from user space!) and - * then fed into the UARTs during interrupts. Will use a classic ring - * queue here for this. The good thing about this type of ring queue - * is that the head and tail pointers can be updated without interrupt - * protection - since "write" code only needs to change the head, and - * interrupt code only needs to change the tail. - */ -struct stlrq { - char *buf; - char *head; - char *tail; -}; - -/* - * Port, panel and board structures to hold status info about each. - * The board structure contains pointers to structures for each panel - * connected to it, and in turn each panel structure contains pointers - * for each port structure for each port on that panel. Note that - * the port structure also contains the board and panel number that it - * is associated with, this makes it (fairly) easy to get back to the - * board/panel info for a port. - */ -struct stlport { - unsigned long magic; - struct tty_port port; - unsigned int portnr; - unsigned int panelnr; - unsigned int brdnr; - int ioaddr; - int uartaddr; - unsigned int pagenr; - unsigned long istate; - int baud_base; - int custom_divisor; - int close_delay; - int closing_wait; - int openwaitcnt; - int brklen; - unsigned int sigs; - unsigned int rxignoremsk; - unsigned int rxmarkmsk; - unsigned int imr; - unsigned int crenable; - unsigned long clk; - unsigned long hwid; - void *uartp; - comstats_t stats; - struct stlrq tx; -}; - -struct stlpanel { - unsigned long magic; - unsigned int panelnr; - unsigned int brdnr; - unsigned int pagenr; - unsigned int nrports; - int iobase; - void *uartp; - void (*isr)(struct stlpanel *panelp, unsigned int iobase); - unsigned int hwid; - unsigned int ackmask; - struct stlport *ports[STL_PORTSPERPANEL]; -}; - -struct stlbrd { - unsigned long magic; - unsigned int brdnr; - unsigned int brdtype; - unsigned int state; - unsigned int nrpanels; - unsigned int nrports; - unsigned int nrbnks; - int irq; - int irqtype; - int (*isr)(struct stlbrd *brdp); - unsigned int ioaddr1; - unsigned int ioaddr2; - unsigned int iosize1; - unsigned int iosize2; - unsigned int iostatus; - unsigned int ioctrl; - unsigned int ioctrlval; - unsigned int hwid; - unsigned long clk; - unsigned int bnkpageaddr[STL_MAXBANKS]; - unsigned int bnkstataddr[STL_MAXBANKS]; - struct stlpanel *bnk2panel[STL_MAXBANKS]; - struct stlpanel *panels[STL_MAXPANELS]; -}; - - -/* - * Define MAGIC numbers used for above structures. - */ -#define STL_PORTMAGIC 0x5a7182c9 -#define STL_PANELMAGIC 0x7ef621a1 -#define STL_BOARDMAGIC 0xa2267f52 - -/*****************************************************************************/ -#endif -- cgit v0.10.2 From 4a055c9c9e1b9c6ea677a3f8187e70339ff47358 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 8 Jun 2012 11:37:00 +0200 Subject: Delete generic_serial.h Commit bb2a97e9ccd525dd9c3326988e8c676d15d3e12a ("Staging: delete generic_serial drivers") left generic_serial.h unused: nothing in the tree includes it anymore. It is still exported, but since nothing in the kernel uses the named constants this header provides, that seems pointless. Delete this header too. Signed-off-by: Paul Bolle Cc: Arnd Bergmann Cc: Alan Cox Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 0a8bcb6..cf41085 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -138,7 +138,6 @@ header-y += fuse.h header-y += futex.h header-y += gameport.h header-y += gen_stats.h -header-y += generic_serial.h header-y += genetlink.h header-y += gfs2_ondisk.h header-y += gigaset_dev.h diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h deleted file mode 100644 index 79b3eb3..0000000 --- a/include/linux/generic_serial.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * generic_serial.h - * - * Copyright (C) 1998 R.E.Wolff@BitWizard.nl - * - * written for the SX serial driver. - * - * Version 0.1 -- December, 1998. - */ - -#ifndef GENERIC_SERIAL_H -#define GENERIC_SERIAL_H - -#warning Use of this header is deprecated. -#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless. - -/* Flags */ -/* Warning: serial.h defines some ASYNC_ flags, they say they are "only" - used in serial.c, but they are also used in all other serial drivers. - Make sure they don't clash with these here... */ -#define GS_TX_INTEN 0x00800000 -#define GS_RX_INTEN 0x00400000 -#define GS_ACTIVE 0x00200000 - -#define GS_TYPE_NORMAL 1 - -#define GS_DEBUG_FLUSH 0x00000001 -#define GS_DEBUG_BTR 0x00000002 -#define GS_DEBUG_TERMIOS 0x00000004 -#define GS_DEBUG_STUFF 0x00000008 -#define GS_DEBUG_CLOSE 0x00000010 -#define GS_DEBUG_FLOW 0x00000020 -#define GS_DEBUG_WRITE 0x00000040 - -#endif -- cgit v0.10.2 From 7cd88831feb03cadb355d5fb2b18ebe284c1f1e3 Mon Sep 17 00:00:00 2001 From: Kyoungil Kim Date: Sun, 20 May 2012 17:45:54 +0900 Subject: serial: samsung: Remove NULL checking for baud clock Signed-off-by: Kyoungil Kim Suggested-by: Russell King Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index d8b0aee..5668538 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -529,7 +529,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, switch (level) { case 3: - if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) + if (!IS_ERR(ourport->baudclk)) clk_disable(ourport->baudclk); clk_disable(ourport->clk); @@ -538,7 +538,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, case 0: clk_enable(ourport->clk); - if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) + if (!IS_ERR(ourport->baudclk)) clk_enable(ourport->baudclk); break; @@ -604,7 +604,6 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, char clkname[MAX_CLK_NAME_LENGTH]; int calc_deviation, deviation = (1 << 30) - 1; - *best_clk = NULL; clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel : ourport->info->def_clk_sel; for (cnt = 0; cnt < info->num_clks; cnt++) { @@ -613,7 +612,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, sprintf(clkname, "clk_uart_baud%d", cnt); clk = clk_get(ourport->port.dev, clkname); - if (IS_ERR_OR_NULL(clk)) + if (IS_ERR(clk)) continue; rate = clk_get_rate(clk); @@ -684,7 +683,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, { struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); - struct clk *clk = NULL; + struct clk *clk = ERR_PTR(-EINVAL); unsigned long flags; unsigned int baud, quot, clk_sel = 0; unsigned int ulcon; @@ -705,7 +704,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel); if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; - if (!clk) + if (IS_ERR(clk)) return; /* check to see if we need to change clock source */ @@ -713,9 +712,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, if (ourport->baudclk != clk) { s3c24xx_serial_setsource(port, clk_sel); - if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { + if (!IS_ERR(ourport->baudclk)) { clk_disable(ourport->baudclk); - ourport->baudclk = NULL; + ourport->baudclk = ERR_PTR(-EINVAL); } clk_enable(clk); @@ -1160,6 +1159,9 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, struct uart_port *port = s3c24xx_dev_to_port(dev); struct s3c24xx_uart_port *ourport = to_ourport(port); + if (IS_ERR(ourport->baudclk)) + return -EINVAL; + return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name); } @@ -1200,6 +1202,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) return -ENODEV; } + ourport->baudclk = ERR_PTR(-EINVAL); ourport->info = ourport->drv_data->info; ourport->cfg = (pdev->dev.platform_data) ? (struct s3c2410_uartcfg *)pdev->dev.platform_data : @@ -1387,7 +1390,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud, sprintf(clk_name, "clk_uart_baud%d", clk_sel); clk = clk_get(port->dev, clk_name); - if (!IS_ERR(clk) && clk != NULL) + if (!IS_ERR(clk)) rate = clk_get_rate(clk); else rate = 1; -- cgit v0.10.2 From 25f04ad423e5eb40c33a904db5a0d2c7e3bf08f5 Mon Sep 17 00:00:00 2001 From: Kyoungil Kim Date: Sun, 20 May 2012 17:49:31 +0900 Subject: serial: samsung: Fixed wrong comparison for baudclk_rate port->baudclk_rate should be compared to the rate of port->baudclk, because port->baudclk_rate was assigned as the rate of port->baudclk previously. So to check that the current baudclk rate is same as previous rate, the target of comparison sholud be the rate of port->baudclk. Signed-off-by: Jun-Ho, Yoon Signed-off-by: Kyoungil Kim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 5668538..cefdd2d 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1013,10 +1013,10 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, * a disturbance in the clock-rate over the change. */ - if (IS_ERR(port->clk)) + if (IS_ERR(port->baudclk)) goto exit; - if (port->baudclk_rate == clk_get_rate(port->clk)) + if (port->baudclk_rate == clk_get_rate(port->baudclk)) goto exit; if (val == CPUFREQ_PRECHANGE) { -- cgit v0.10.2 From 7b15e1d9e342aca6c65f4824f1957f5245fcd87a Mon Sep 17 00:00:00 2001 From: KeyYoung Park Date: Wed, 30 May 2012 17:29:55 +0900 Subject: serial: samsung: protect NULL dereference of clock name When priting the serial clock source, if clock source name is null, kernel reference NULL point. Signed-off-by: KeyYoung Park Signed-off-by: Huisung Kang Signed-off-by: Kyoungil Kim Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index cefdd2d..d57f165 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1162,7 +1162,8 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev, if (IS_ERR(ourport->baudclk)) return -EINVAL; - return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name); + return snprintf(buf, PAGE_SIZE, "* %s\n", + ourport->baudclk->name ?: "(null)"); } static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL); -- cgit v0.10.2 From 7d0b066fbb912debc18e9556187f2d0313b8469e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 21 May 2012 21:57:39 +0200 Subject: serial/imx: make devdata member point to const data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is only cosmetic for now. In case that http://mid.gmane.org/1335171381-24869-1-git-send-email-u.kleine-koenig@pengutronix.de will be applied, it fixes a warning drivers/tty/serial/imx.c: In function 'serial_imx_probe_dt': drivers/tty/serial/imx.c:1430:17: warning: assignment discards 'const' qualifier from pointer target type [enabled by default] though. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 4ef7473..0af4eec 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -207,7 +207,7 @@ struct imx_port { unsigned short trcv_delay; /* transceiver delay */ struct clk *clk_ipg; struct clk *clk_per; - struct imx_uart_data *devdata; + const struct imx_uart_data *devdata; }; struct imx_port_ucrs { -- cgit v0.10.2 From dabfb351db690964f6c5f5729d4f407586f69a4f Mon Sep 17 00:00:00 2001 From: Corbin Date: Wed, 23 May 2012 09:37:31 -0500 Subject: serial_core: Update buffer overrun statistics. Currently, serial drivers don't report buffer overruns. When a buffer overrun occurs, tty_insert_flip_char returns 0, and no attempt is made to insert that same character again (i.e. it is lost). This patch reports buffer overruns via the buf_overrun field in the port's icount structure. Signed-off-by: Corbin Atkinson Cc: Jiri Slaby Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 246b823..a21dc8e 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2527,14 +2527,16 @@ void uart_insert_char(struct uart_port *port, unsigned int status, struct tty_struct *tty = port->state->port.tty; if ((status & port->ignore_status_mask & ~overrun) == 0) - tty_insert_flip_char(tty, ch, flag); + if (tty_insert_flip_char(tty, ch, flag) == 0) + ++port->icount.buf_overrun; /* * Overrun is special. Since it's reported immediately, * it doesn't affect the current character. */ if (status & ~port->ignore_status_mask & overrun) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0) + ++port->icount.buf_overrun; } EXPORT_SYMBOL_GPL(uart_insert_char); -- cgit v0.10.2 From 7a5145965c9807732135630642c49f280b375f56 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 11 Jun 2012 21:57:13 +0200 Subject: serial/8250: Add LPC3220 standard UART type LPC32xx has "Standard" UARTs that are actually 16550A compatible but have bigger FIFOs. Since the already supported 16X50 line still doesn't match here, we agreed on adding a new type. Signed-off-by: Roland Stigge Acked-by: Alan Cox Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 47d061b..349d12c 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -282,6 +282,14 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR, }, + [PORT_LPC3220] = { + .name = "LPC3220", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | + UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, + .flags = UART_CAP_FIFO, + }, }; /* Uart divisor latch read */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 65db992..0253c20 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -47,7 +47,8 @@ #define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */ #define PORT_TEGRA 20 /* NVIDIA Tegra internal UART */ #define PORT_XR17D15X 21 /* Exar XR17D15x UART */ -#define PORT_MAX_8250 21 /* max port ID */ +#define PORT_LPC3220 22 /* NXP LPC32xx SoC "Standard" UART */ +#define PORT_MAX_8250 22 /* max port ID */ /* * ARM specific type numbers. These are not currently guaranteed -- cgit v0.10.2 From e4305f0c500cc2b8ca8d6ca2fb74fb76bf2cb6ad Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 11 Jun 2012 21:57:14 +0200 Subject: serial/of-serial: Add LPC3220 standard UART compatible string This patch adds a "compatible" string for the new 8250 UART type PORT_LPC3220. This is necessary for initializing LPC32xx UARTs via DT. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt index b8b27b0..0847fde 100644 --- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -9,6 +9,7 @@ Required properties: - "ns16750" - "ns16850" - "nvidia,tegra20-uart" + - "nxp,lpc3220-uart" - "ibm,qpace-nwp-serial" - "serial" if the port type is unknown. - reg : offset and length of the register set for the device. diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 5410c06..34e7187 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -208,6 +208,7 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = { { .compatible = "ns16750", .data = (void *)PORT_16750, }, { .compatible = "ns16850", .data = (void *)PORT_16850, }, { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, + { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL { .compatible = "ibm,qpace-nwp-serial", .data = (void *)PORT_NWPSERIAL, }, -- cgit v0.10.2 From 596f93f50e2d1a926bbb6c73aa7ee7fd862b7062 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 11 Jun 2012 22:04:12 +0200 Subject: serial: Add driver for LPC32xx High Speed UARTs This patch adds a driver for the 3 High Speed UARTs of the LPC32xx SoC that support up to 921600bps. These UARTs are different from the 4 "Standard" UARTs of the LPC32xx. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt new file mode 100644 index 0000000..0d439df --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt @@ -0,0 +1,14 @@ +* NXP LPC32xx SoC High Speed UART + +Required properties: +- compatible: Should be "nxp,lpc3220-hsuart" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt + +Example: + + uart1: serial@40014000 { + compatible = "nxp,lpc3220-hsuart"; + reg = <0x40014000 0x1000>; + interrupts = <26 0>; + }; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 070b442..0020786 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -704,6 +704,25 @@ config SERIAL_PNX8XXX_CONSOLE If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330 and you want to use serial console, say Y. Otherwise, say N. +config SERIAL_HS_LPC32XX + tristate "LPC32XX high speed serial port support" + depends on ARCH_LPC32XX && OF + select SERIAL_CORE + help + Support for the LPC32XX high speed serial ports (up to 900kbps). + Those are UARTs completely different from the Standard UARTs on the + LPC32XX SoC. + Choose M or Y here to build this driver. + +config SERIAL_HS_LPC32XX_CONSOLE + bool "Enable LPC32XX high speed UART serial console" + depends on SERIAL_HS_LPC32XX + select SERIAL_CORE_CONSOLE + help + If you would like to be able to use one of the high speed serial + ports on the LPC32XX as the console, you can do so by answering + Y to this option. + config SERIAL_CORE tristate diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 7257c5d..8a5df38 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_ZS) += zs.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c new file mode 100644 index 0000000..ba3af3b --- /dev/null +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -0,0 +1,823 @@ +/* + * High Speed Serial Ports on NXP LPC32xx SoC + * + * Authors: Kevin Wells + * Roland Stigge + * + * Copyright (C) 2010 NXP Semiconductors + * Copyright (C) 2012 Roland Stigge + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * High Speed UART register offsets + */ +#define LPC32XX_HSUART_FIFO(x) ((x) + 0x00) +#define LPC32XX_HSUART_LEVEL(x) ((x) + 0x04) +#define LPC32XX_HSUART_IIR(x) ((x) + 0x08) +#define LPC32XX_HSUART_CTRL(x) ((x) + 0x0C) +#define LPC32XX_HSUART_RATE(x) ((x) + 0x10) + +#define LPC32XX_HSU_BREAK_DATA (1 << 10) +#define LPC32XX_HSU_ERROR_DATA (1 << 9) +#define LPC32XX_HSU_RX_EMPTY (1 << 8) + +#define LPC32XX_HSU_TX_LEV(n) (((n) >> 8) & 0xFF) +#define LPC32XX_HSU_RX_LEV(n) ((n) & 0xFF) + +#define LPC32XX_HSU_TX_INT_SET (1 << 6) +#define LPC32XX_HSU_RX_OE_INT (1 << 5) +#define LPC32XX_HSU_BRK_INT (1 << 4) +#define LPC32XX_HSU_FE_INT (1 << 3) +#define LPC32XX_HSU_RX_TIMEOUT_INT (1 << 2) +#define LPC32XX_HSU_RX_TRIG_INT (1 << 1) +#define LPC32XX_HSU_TX_INT (1 << 0) + +#define LPC32XX_HSU_HRTS_INV (1 << 21) +#define LPC32XX_HSU_HRTS_TRIG_8B (0x0 << 19) +#define LPC32XX_HSU_HRTS_TRIG_16B (0x1 << 19) +#define LPC32XX_HSU_HRTS_TRIG_32B (0x2 << 19) +#define LPC32XX_HSU_HRTS_TRIG_48B (0x3 << 19) +#define LPC32XX_HSU_HRTS_EN (1 << 18) +#define LPC32XX_HSU_TMO_DISABLED (0x0 << 16) +#define LPC32XX_HSU_TMO_INACT_4B (0x1 << 16) +#define LPC32XX_HSU_TMO_INACT_8B (0x2 << 16) +#define LPC32XX_HSU_TMO_INACT_16B (0x3 << 16) +#define LPC32XX_HSU_HCTS_INV (1 << 15) +#define LPC32XX_HSU_HCTS_EN (1 << 14) +#define LPC32XX_HSU_OFFSET(n) ((n) << 9) +#define LPC32XX_HSU_BREAK (1 << 8) +#define LPC32XX_HSU_ERR_INT_EN (1 << 7) +#define LPC32XX_HSU_RX_INT_EN (1 << 6) +#define LPC32XX_HSU_TX_INT_EN (1 << 5) +#define LPC32XX_HSU_RX_TL1B (0x0 << 2) +#define LPC32XX_HSU_RX_TL4B (0x1 << 2) +#define LPC32XX_HSU_RX_TL8B (0x2 << 2) +#define LPC32XX_HSU_RX_TL16B (0x3 << 2) +#define LPC32XX_HSU_RX_TL32B (0x4 << 2) +#define LPC32XX_HSU_RX_TL48B (0x5 << 2) +#define LPC32XX_HSU_TX_TLEMPTY (0x0 << 0) +#define LPC32XX_HSU_TX_TL0B (0x0 << 0) +#define LPC32XX_HSU_TX_TL4B (0x1 << 0) +#define LPC32XX_HSU_TX_TL8B (0x2 << 0) +#define LPC32XX_HSU_TX_TL16B (0x3 << 0) + +#define MODNAME "lpc32xx_hsuart" + +struct lpc32xx_hsuart_port { + struct uart_port port; +}; + +#define FIFO_READ_LIMIT 128 +#define MAX_PORTS 3 +#define LPC32XX_TTY_NAME "ttyTX" +static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS]; + +#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE +static void wait_for_xmit_empty(struct uart_port *port) +{ + unsigned int timeout = 10000; + + do { + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL( + port->membase))) == 0) + break; + if (--timeout == 0) + break; + udelay(1); + } while (1); +} + +static void wait_for_xmit_ready(struct uart_port *port) +{ + unsigned int timeout = 10000; + + while (1) { + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL( + port->membase))) < 32) + break; + if (--timeout == 0) + break; + udelay(1); + } +} + +static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch) +{ + wait_for_xmit_ready(port); + writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase)); +} + +static void lpc32xx_hsuart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index]; + unsigned long flags; + int locked = 1; + + touch_nmi_watchdog(); + local_irq_save(flags); + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + + uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar); + wait_for_xmit_empty(&up->port); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); +} + +static int __init lpc32xx_hsuart_console_setup(struct console *co, + char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= MAX_PORTS) + co->index = 0; + + port = &lpc32xx_hs_ports[co->index].port; + if (!port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver lpc32xx_hsuart_reg; +static struct console lpc32xx_hsuart_console = { + .name = LPC32XX_TTY_NAME, + .write = lpc32xx_hsuart_console_write, + .device = uart_console_device, + .setup = lpc32xx_hsuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lpc32xx_hsuart_reg, +}; + +static int __init lpc32xx_hsuart_console_init(void) +{ + register_console(&lpc32xx_hsuart_console); + return 0; +} +console_initcall(lpc32xx_hsuart_console_init); + +#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console) +#else +#define LPC32XX_HSUART_CONSOLE NULL +#endif + +static struct uart_driver lpc32xx_hs_reg = { + .owner = THIS_MODULE, + .driver_name = MODNAME, + .dev_name = LPC32XX_TTY_NAME, + .nr = MAX_PORTS, + .cons = LPC32XX_HSUART_CONSOLE, +}; +static int uarts_registered; + +static unsigned int __serial_get_clock_div(unsigned long uartclk, + unsigned long rate) +{ + u32 div, goodrate, hsu_rate, l_hsu_rate, comprate; + u32 rate_diff; + + /* Find the closest divider to get the desired clock rate */ + div = uartclk / rate; + goodrate = hsu_rate = (div / 14) - 1; + if (hsu_rate != 0) + hsu_rate--; + + /* Tweak divider */ + l_hsu_rate = hsu_rate + 3; + rate_diff = 0xFFFFFFFF; + + while (hsu_rate < l_hsu_rate) { + comprate = uartclk / ((hsu_rate + 1) * 14); + if (abs(comprate - rate) < rate_diff) { + goodrate = hsu_rate; + rate_diff = abs(comprate - rate); + } + + hsu_rate++; + } + if (hsu_rate > 0xFF) + hsu_rate = 0xFF; + + return goodrate; +} + +static void __serial_uart_flush(struct uart_port *port) +{ + u32 tmp; + int cnt = 0; + + while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) && + (cnt++ < FIFO_READ_LIMIT)) + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); +} + +static void __serial_lpc32xx_rx(struct uart_port *port) +{ + unsigned int tmp, flag; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + + if (!tty) { + /* Discard data: no tty available */ + while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) & + LPC32XX_HSU_RX_EMPTY)) + ; + + return; + } + + /* Read data from FIFO and push into terminal */ + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + while (!(tmp & LPC32XX_HSU_RX_EMPTY)) { + flag = TTY_NORMAL; + port->icount.rx++; + + if (tmp & LPC32XX_HSU_ERROR_DATA) { + /* Framing error */ + writel(LPC32XX_HSU_FE_INT, + LPC32XX_HSUART_IIR(port->membase)); + port->icount.frame++; + flag = TTY_FRAME; + tty_insert_flip_char(tty, 0, TTY_FRAME); + } + + tty_insert_flip_char(tty, (tmp & 0xFF), flag); + + tmp = readl(LPC32XX_HSUART_FIFO(port->membase)); + } + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + +static void __serial_lpc32xx_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int tmp; + + if (port->x_char) { + writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase)); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + goto exit_tx; + + /* Transfer data */ + while (LPC32XX_HSU_TX_LEV(readl( + LPC32XX_HSUART_LEVEL(port->membase))) < 64) { + writel((u32) xmit->buf[xmit->tail], + LPC32XX_HSUART_FIFO(port->membase)); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + +exit_tx: + if (uart_circ_empty(xmit)) { + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + } +} + +static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + u32 status; + + spin_lock(&port->lock); + + /* Read UART status and clear latched interrupts */ + status = readl(LPC32XX_HSUART_IIR(port->membase)); + + if (status & LPC32XX_HSU_BRK_INT) { + /* Break received */ + writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase)); + port->icount.brk++; + uart_handle_break(port); + } + + /* Framing error */ + if (status & LPC32XX_HSU_FE_INT) + writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase)); + + if (status & LPC32XX_HSU_RX_OE_INT) { + /* Receive FIFO overrun */ + writel(LPC32XX_HSU_RX_OE_INT, + LPC32XX_HSUART_IIR(port->membase)); + port->icount.overrun++; + if (tty) { + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_schedule_flip(tty); + } + } + + /* Data received? */ + if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) { + __serial_lpc32xx_rx(port); + if (tty) + tty_flip_buffer_push(tty); + } + + /* Transmit data request? */ + if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) { + writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase)); + __serial_lpc32xx_tx(port); + } + + spin_unlock(&port->lock); + tty_kref_put(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port) +{ + unsigned int ret = 0; + + if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0) + ret = TIOCSER_TEMT; + + return ret; +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_set_mctrl(struct uart_port *port, + unsigned int mctrl) +{ + /* No signals are supported on HS UARTs */ +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port) +{ + /* No signals are supported on HS UARTs */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_stop_tx(struct uart_port *port) +{ + u32 tmp; + + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_start_tx(struct uart_port *port) +{ + u32 tmp; + + __serial_lpc32xx_tx(port); + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp |= LPC32XX_HSU_TX_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_stop_rx(struct uart_port *port) +{ + u32 tmp; + + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN); + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT | + LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase)); +} + +/* port->lock held by caller. */ +static void serial_lpc32xx_enable_ms(struct uart_port *port) +{ + /* Modem status is not supported */ +} + +/* port->lock is not held. */ +static void serial_lpc32xx_break_ctl(struct uart_port *port, + int break_state) +{ + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&port->lock, flags); + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + if (break_state != 0) + tmp |= LPC32XX_HSU_BREAK; + else + tmp &= ~LPC32XX_HSU_BREAK; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */ +static void lpc32xx_loopback_set(resource_size_t mapbase, int state) +{ + int bit; + u32 tmp; + + switch (mapbase) { + case LPC32XX_HS_UART1_BASE: + bit = 0; + break; + case LPC32XX_HS_UART2_BASE: + bit = 1; + break; + case LPC32XX_HS_UART7_BASE: + bit = 6; + break; + default: + WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase); + return; + } + + tmp = readl(LPC32XX_UARTCTL_CLOOP); + if (state) + tmp |= (1 << bit); + else + tmp &= ~(1 << bit); + writel(tmp, LPC32XX_UARTCTL_CLOOP); +} + +/* port->lock is not held. */ +static int serial_lpc32xx_startup(struct uart_port *port) +{ + int retval; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&port->lock, flags); + + __serial_uart_flush(port); + + writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT | + LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT), + LPC32XX_HSUART_IIR(port->membase)); + + writel(0xFF, LPC32XX_HSUART_RATE(port->membase)); + + /* + * Set receiver timeout, HSU offset of 20, no break, no interrupts, + * and default FIFO trigger levels + */ + tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */ + + spin_unlock_irqrestore(&port->lock, flags); + + retval = request_irq(port->irq, serial_lpc32xx_interrupt, + 0, MODNAME, port); + if (!retval) + writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN), + LPC32XX_HSUART_CTRL(port->membase)); + + return retval; +} + +/* port->lock is not held. */ +static void serial_lpc32xx_shutdown(struct uart_port *port) +{ + u32 tmp; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */ + + spin_unlock_irqrestore(&port->lock, flags); + + free_irq(port->irq, port); +} + +/* port->lock is not held. */ +static void serial_lpc32xx_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned long flags; + unsigned int baud, quot; + u32 tmp; + + /* Always 8-bit, no parity, 1 stop bit */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + termios->c_cflag |= CS8; + + termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS); + + baud = uart_get_baud_rate(port, termios, old, 0, + port->uartclk / 14); + + quot = __serial_get_clock_div(port->uartclk, baud); + + spin_lock_irqsave(&port->lock, flags); + + /* Ignore characters? */ + tmp = readl(LPC32XX_HSUART_CTRL(port->membase)); + if ((termios->c_cflag & CREAD) == 0) + tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN); + else + tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN; + writel(tmp, LPC32XX_HSUART_CTRL(port->membase)); + + writel(quot, LPC32XX_HSUART_RATE(port->membase)); + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} + +static const char *serial_lpc32xx_type(struct uart_port *port) +{ + return MODNAME; +} + +static void serial_lpc32xx_release_port(struct uart_port *port) +{ + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) { + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, SZ_4K); + } +} + +static int serial_lpc32xx_request_port(struct uart_port *port) +{ + int ret = -ENODEV; + + if ((port->iotype == UPIO_MEM32) && (port->mapbase)) { + ret = 0; + + if (!request_mem_region(port->mapbase, SZ_4K, MODNAME)) + ret = -EBUSY; + else if (port->flags & UPF_IOREMAP) { + port->membase = ioremap(port->mapbase, SZ_4K); + if (!port->membase) { + release_mem_region(port->mapbase, SZ_4K); + ret = -ENOMEM; + } + } + } + + return ret; +} + +static void serial_lpc32xx_config_port(struct uart_port *port, int uflags) +{ + int ret; + + ret = serial_lpc32xx_request_port(port); + if (ret < 0) + return; + port->type = PORT_UART00; + port->fifosize = 64; + + __serial_uart_flush(port); + + writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT | + LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT), + LPC32XX_HSUART_IIR(port->membase)); + + writel(0xFF, LPC32XX_HSUART_RATE(port->membase)); + + /* Set receiver timeout, HSU offset of 20, no break, no interrupts, + and default FIFO trigger levels */ + writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B | + LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B, + LPC32XX_HSUART_CTRL(port->membase)); +} + +static int serial_lpc32xx_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UART00) + ret = -EINVAL; + + return ret; +} + +static struct uart_ops serial_lpc32xx_pops = { + .tx_empty = serial_lpc32xx_tx_empty, + .set_mctrl = serial_lpc32xx_set_mctrl, + .get_mctrl = serial_lpc32xx_get_mctrl, + .stop_tx = serial_lpc32xx_stop_tx, + .start_tx = serial_lpc32xx_start_tx, + .stop_rx = serial_lpc32xx_stop_rx, + .enable_ms = serial_lpc32xx_enable_ms, + .break_ctl = serial_lpc32xx_break_ctl, + .startup = serial_lpc32xx_startup, + .shutdown = serial_lpc32xx_shutdown, + .set_termios = serial_lpc32xx_set_termios, + .type = serial_lpc32xx_type, + .release_port = serial_lpc32xx_release_port, + .request_port = serial_lpc32xx_request_port, + .config_port = serial_lpc32xx_config_port, + .verify_port = serial_lpc32xx_verify_port, +}; + +/* + * Register a set of serial devices attached to a platform device + */ +static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered]; + int ret = 0; + struct resource *res; + + if (uarts_registered >= MAX_PORTS) { + dev_err(&pdev->dev, + "Error: Number of possible ports exceeded (%d)!\n", + uarts_registered + 1); + return -ENXIO; + } + + memset(p, 0, sizeof(*p)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Error getting mem resource for HS UART port %d\n", + uarts_registered); + return -ENXIO; + } + p->port.mapbase = res->start; + p->port.membase = NULL; + + p->port.irq = platform_get_irq(pdev, 0); + if (p->port.irq < 0) { + dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n", + uarts_registered); + return p->port.irq; + } + + p->port.iotype = UPIO_MEM32; + p->port.uartclk = LPC32XX_MAIN_OSC_FREQ; + p->port.regshift = 2; + p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP; + p->port.dev = &pdev->dev; + p->port.ops = &serial_lpc32xx_pops; + p->port.line = uarts_registered++; + spin_lock_init(&p->port.lock); + + /* send port to loopback mode by default */ + lpc32xx_loopback_set(p->port.mapbase, 1); + + ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port); + + platform_set_drvdata(pdev, p); + + return ret; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_remove_one_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} + + +#ifdef CONFIG_PM +static int serial_hs_lpc32xx_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_suspend_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} + +static int serial_hs_lpc32xx_resume(struct platform_device *pdev) +{ + struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev); + + uart_resume_port(&lpc32xx_hs_reg, &p->port); + + return 0; +} +#else +#define serial_hs_lpc32xx_suspend NULL +#define serial_hs_lpc32xx_resume NULL +#endif + +static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = { + { .compatible = "nxp,lpc3220-hsuart" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids); + +static struct platform_driver serial_hs_lpc32xx_driver = { + .probe = serial_hs_lpc32xx_probe, + .remove = __devexit_p(serial_hs_lpc32xx_remove), + .suspend = serial_hs_lpc32xx_suspend, + .resume = serial_hs_lpc32xx_resume, + .driver = { + .name = MODNAME, + .owner = THIS_MODULE, + .of_match_table = serial_hs_lpc32xx_dt_ids, + }, +}; + +static int __init lpc32xx_hsuart_init(void) +{ + int ret; + + ret = uart_register_driver(&lpc32xx_hs_reg); + if (ret) + return ret; + + ret = platform_driver_register(&serial_hs_lpc32xx_driver); + if (ret) + uart_unregister_driver(&lpc32xx_hs_reg); + + return ret; +} + +static void __exit lpc32xx_hsuart_exit(void) +{ + platform_driver_unregister(&serial_hs_lpc32xx_driver); + uart_unregister_driver(&lpc32xx_hs_reg); +} + +module_init(lpc32xx_hsuart_init); +module_exit(lpc32xx_hsuart_exit); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_AUTHOR("Roland Stigge "); +MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From ee4cd1b225368abed7e0f4d344f1e9a93e87b98e Mon Sep 17 00:00:00 2001 From: Shawn Bohrer Date: Mon, 28 May 2012 15:20:47 -0500 Subject: 8250_pci: Remove duplicate struct pciserial_board pbn_exsys_4055 is the same thing as pbn_b2_4_115200 so replace it with the standard pattern. Signed-off-by: Shawn Bohrer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 28e7c7c..66e5909 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1887,7 +1887,6 @@ enum pci_board_num_t { pbn_panacom, pbn_panacom2, pbn_panacom4, - pbn_exsys_4055, pbn_plx_romulus, pbn_oxsemi, pbn_oxsemi_1_4000000, @@ -2393,13 +2392,6 @@ static struct pciserial_board pci_boards[] __devinitdata = { .reg_shift = 7, }, - [pbn_exsys_4055] = { - .flags = FL_BASE2, - .num_ports = 4, - .base_baud = 115200, - .uart_offset = 8, - }, - /* I think this entry is broken - the first_offset looks wrong --rmk */ [pbn_plx_romulus] = { .flags = FL_BASE2, @@ -3193,7 +3185,7 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0, - pbn_exsys_4055 }, + pbn_b2_4_115200 }, /* * Megawolf Romulus PCI Serial Card, from Mike Hudson * (Exoray@isys.ca) -- cgit v0.10.2 From 718c4ca1f721be3ae67f9ff7d43b9a910e4a1ec3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:15 +0200 Subject: TTY: cyclades, add local pointer for card cy_pci_probe and cy_detect_isa reference cy_card[card_no] many times. It makes the code hard to read. Let us add a local variable holding a pointer to the card indexed by card_no and use that. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index e61cabd..cff5468 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -3289,6 +3289,7 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr, static int __init cy_detect_isa(void) { #ifdef CONFIG_ISA + struct cyclades_card *card; unsigned short cy_isa_irq, nboard; void __iomem *cy_isa_address; unsigned short i, j, cy_isa_nchan; @@ -3349,7 +3350,8 @@ static int __init cy_detect_isa(void) } /* fill the next cy_card structure available */ for (j = 0; j < NR_CARDS; j++) { - if (cy_card[j].base_addr == NULL) + card = &cy_card[j]; + if (card->base_addr == NULL) break; } if (j == NR_CARDS) { /* no more cy_cards available */ @@ -3363,7 +3365,7 @@ static int __init cy_detect_isa(void) /* allocate IRQ */ if (request_irq(cy_isa_irq, cyy_interrupt, - 0, "Cyclom-Y", &cy_card[j])) { + 0, "Cyclom-Y", card)) { printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " "could not allocate IRQ#%d.\n", (unsigned long)cy_isa_address, cy_isa_irq); @@ -3372,16 +3374,16 @@ static int __init cy_detect_isa(void) } /* set cy_card */ - cy_card[j].base_addr = cy_isa_address; - cy_card[j].ctl_addr.p9050 = NULL; - cy_card[j].irq = (int)cy_isa_irq; - cy_card[j].bus_index = 0; - cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; - cy_card[j].nports = cy_isa_nchan; - if (cy_init_card(&cy_card[j])) { - cy_card[j].base_addr = NULL; - free_irq(cy_isa_irq, &cy_card[j]); + card->base_addr = cy_isa_address; + card->ctl_addr.p9050 = NULL; + card->irq = (int)cy_isa_irq; + card->bus_index = 0; + card->first_line = cy_next_channel; + card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; + card->nports = cy_isa_nchan; + if (cy_init_card(card)) { + card->base_addr = NULL; + free_irq(cy_isa_irq, card); iounmap(cy_isa_address); continue; } @@ -3695,6 +3697,7 @@ err: static int __devinit cy_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct cyclades_card *card; void __iomem *addr0 = NULL, *addr2 = NULL; char *card_name = NULL; u32 uninitialized_var(mailbox); @@ -3829,7 +3832,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } /* fill the next cy_card structure available */ for (card_no = 0; card_no < NR_CARDS; card_no++) { - if (cy_card[card_no].base_addr == NULL) + card = &cy_card[card_no]; + if (card->base_addr == NULL) break; } if (card_no == NR_CARDS) { /* no more cy_cards available */ @@ -3843,27 +3847,26 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { /* allocate IRQ */ retval = request_irq(irq, cyy_interrupt, - IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]); + IRQF_SHARED, "Cyclom-Y", card); if (retval) { dev_err(&pdev->dev, "could not allocate IRQ\n"); goto err_unmap; } - cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP; + card->num_chips = nchan / CyPORTS_PER_CHIP; } else { struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS; struct ZFW_CTRL __iomem *zfw_ctrl; zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff); - cy_card[card_no].hw_ver = mailbox; - cy_card[card_no].num_chips = (unsigned int)-1; - cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl; + card->hw_ver = mailbox; + card->num_chips = (unsigned int)-1; + card->board_ctrl = &zfw_ctrl->board_ctrl; #ifdef CONFIG_CYZ_INTR /* allocate IRQ only if board has an IRQ */ if (irq != 0 && irq != 255) { retval = request_irq(irq, cyz_interrupt, - IRQF_SHARED, "Cyclades-Z", - &cy_card[card_no]); + IRQF_SHARED, "Cyclades-Z", card); if (retval) { dev_err(&pdev->dev, "could not allocate IRQ\n"); goto err_unmap; @@ -3873,17 +3876,17 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } /* set cy_card */ - cy_card[card_no].base_addr = addr2; - cy_card[card_no].ctl_addr.p9050 = addr0; - cy_card[card_no].irq = irq; - cy_card[card_no].bus_index = 1; - cy_card[card_no].first_line = cy_next_channel; - cy_card[card_no].nports = nchan; - retval = cy_init_card(&cy_card[card_no]); + card->base_addr = addr2; + card->ctl_addr.p9050 = addr0; + card->irq = irq; + card->bus_index = 1; + card->first_line = cy_next_channel; + card->nports = nchan; + retval = cy_init_card(card); if (retval) goto err_null; - pci_set_drvdata(pdev, &cy_card[card_no]); + pci_set_drvdata(pdev, card); if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { @@ -3915,8 +3918,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, return 0; err_null: - cy_card[card_no].base_addr = NULL; - free_irq(irq, &cy_card[card_no]); + card->base_addr = NULL; + free_irq(irq, card); err_unmap: iounmap(addr0); if (addr2) -- cgit v0.10.2 From a3cc9fcff84c4c8aaecda2420acd89a1418d57e9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:16 +0200 Subject: TTY: ircomm, add tty_port And use close/open_wait from there. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index 59ba38bc..365fa6e 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -62,6 +62,7 @@ */ struct ircomm_tty_cb { irda_queue_t queue; /* Must be first */ + struct tty_port port; magic_t magic; int state; /* Connect state */ @@ -97,8 +98,6 @@ struct ircomm_tty_cb { void *skey; void *ckey; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; struct timer_list watchdog_timer; struct work_struct tqueue; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 6b9d5a0..8eeaa8b 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -278,7 +278,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, */ retval = 0; - add_wait_queue(&self->open_wait, &wait); + add_wait_queue(&self->port.open_wait, &wait); IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n", __FILE__,__LINE__, tty->driver->name, self->open_count ); @@ -336,7 +336,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, } __set_current_state(TASK_RUNNING); - remove_wait_queue(&self->open_wait, &wait); + remove_wait_queue(&self->port.open_wait, &wait); if (extra_count) { /* ++ is not atomic, so this should be protected - Jean II */ @@ -381,6 +381,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) return -ENOMEM; } + tty_port_init(&self->port); self->magic = IRCOMM_TTY_MAGIC; self->flow = FLOW_STOP; @@ -393,8 +394,6 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) /* Init some important stuff */ init_timer(&self->watchdog_timer); - init_waitqueue_head(&self->open_wait); - init_waitqueue_head(&self->close_wait); spin_lock_init(&self->spinlock); /* @@ -408,6 +407,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) tty->termios->c_oflag = 0; /* Insert into hash */ + /* FIXME there is a window from find to here */ hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); } /* ++ is not atomic, so this should be protected - Jean II */ @@ -438,7 +438,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) * probably better sleep uninterruptible? */ - if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) { + if (wait_event_interruptible(self->port.close_wait, + !test_bit(ASYNC_B_CLOSING, &self->flags))) { IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n", __func__); return -ERESTARTSYS; @@ -559,11 +560,11 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) if (self->blocked_open) { if (self->close_delay) schedule_timeout_interruptible(self->close_delay); - wake_up_interruptible(&self->open_wait); + wake_up_interruptible(&self->port.open_wait); } self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&self->close_wait); + wake_up_interruptible(&self->port.close_wait); } /* @@ -1011,7 +1012,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty) self->open_count = 0; spin_unlock_irqrestore(&self->spinlock, flags); - wake_up_interruptible(&self->open_wait); + wake_up_interruptible(&self->port.open_wait); } /* @@ -1084,7 +1085,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) (status & IRCOMM_CD) ? "on" : "off"); if (status & IRCOMM_CD) { - wake_up_interruptible(&self->open_wait); + wake_up_interruptible(&self->port.open_wait); } else { IRDA_DEBUG(2, "%s(), Doing serial hangup..\n", __func__ ); @@ -1103,7 +1104,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) tty->hw_stopped = 0; /* Wake up processes blocked on open */ - wake_up_interruptible(&self->open_wait); + wake_up_interruptible(&self->port.open_wait); schedule_work(&self->tqueue); return; diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index b65d66e..bb1e935 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -575,7 +575,7 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self) self->tty->hw_stopped = 0; /* Wake up processes blocked on open */ - wake_up_interruptible(&self->open_wait); + wake_up_interruptible(&self->port.open_wait); } schedule_work(&self->tqueue); -- cgit v0.10.2 From 2a0213cb1e1ca6b2838595b0d70f09ecc4953ba9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:17 +0200 Subject: TTY: ircomm, use close times from tty_port Switch to tty_port->close_delay and closing_wait. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index 365fa6e..b4184d0 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -101,9 +101,6 @@ struct ircomm_tty_cb { struct timer_list watchdog_timer; struct work_struct tqueue; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ - int open_count; int blocked_open; /* # of blocked opens */ diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 8eeaa8b..61e0adc 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -389,8 +389,6 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) INIT_WORK(&self->tqueue, ircomm_tty_do_softint); self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED; self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED; - self->close_delay = 5*HZ/10; - self->closing_wait = 30*HZ; /* Init some important stuff */ init_timer(&self->watchdog_timer); @@ -546,8 +544,8 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent_from_close(tty, self->closing_wait); + if (self->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent_from_close(tty, self->port.closing_wait); ircomm_tty_shutdown(self); @@ -558,8 +556,8 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) self->tty = NULL; if (self->blocked_open) { - if (self->close_delay) - schedule_timeout_interruptible(self->close_delay); + if (self->port.close_delay) + schedule_timeout_interruptible(self->port.close_delay); wake_up_interruptible(&self->port.open_wait); } diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index d0667d6..a6d25e3 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -272,8 +272,8 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self, info.line = self->line; info.flags = self->flags; info.baud_base = self->settings.data_rate; - info.close_delay = self->close_delay; - info.closing_wait = self->closing_wait; + info.close_delay = self->port.close_delay; + info.closing_wait = self->port.closing_wait; /* For compatibility */ info.type = PORT_16550A; -- cgit v0.10.2 From 580d27b449cb8f540bba1cc54066bb44f4e6242d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:18 +0200 Subject: TTY: ircomm, use open counts from tty_port Switch to tty_port->count and blocked_open. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index b4184d0..5e94bad 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -101,9 +101,6 @@ struct ircomm_tty_cb { struct timer_list watchdog_timer; struct work_struct tqueue; - int open_count; - int blocked_open; /* # of blocked opens */ - /* Protect concurent access to : * o self->open_count * o self->ctrl_skb diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 61e0adc..787578f 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -272,7 +272,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, self->open_count is dropped by one, so that + * this loop, self->port.count is dropped by one, so that * mgsl_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ @@ -281,16 +281,16 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, add_wait_queue(&self->port.open_wait, &wait); IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n", - __FILE__,__LINE__, tty->driver->name, self->open_count ); + __FILE__, __LINE__, tty->driver->name, self->port.count); - /* As far as I can see, we protect open_count - Jean II */ + /* As far as I can see, we protect port.count - Jean II */ spin_lock_irqsave(&self->spinlock, flags); if (!tty_hung_up_p(filp)) { extra_count = 1; - self->open_count--; + self->port.count--; } spin_unlock_irqrestore(&self->spinlock, flags); - self->blocked_open++; + self->port.blocked_open++; while (1) { if (tty->termios->c_cflag & CBAUD) { @@ -330,7 +330,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, } IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n", - __FILE__,__LINE__, tty->driver->name, self->open_count ); + __FILE__, __LINE__, tty->driver->name, self->port.count); schedule(); } @@ -341,13 +341,13 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, if (extra_count) { /* ++ is not atomic, so this should be protected - Jean II */ spin_lock_irqsave(&self->spinlock, flags); - self->open_count++; + self->port.count++; spin_unlock_irqrestore(&self->spinlock, flags); } - self->blocked_open--; + self->port.blocked_open--; IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n", - __FILE__,__LINE__, tty->driver->name, self->open_count); + __FILE__, __LINE__, tty->driver->name, self->port.count); if (!retval) self->flags |= ASYNC_NORMAL_ACTIVE; @@ -410,14 +410,14 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) } /* ++ is not atomic, so this should be protected - Jean II */ spin_lock_irqsave(&self->spinlock, flags); - self->open_count++; + self->port.count++; tty->driver_data = self; self->tty = tty; spin_unlock_irqrestore(&self->spinlock, flags); IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name, - self->line, self->open_count); + self->line, self->port.count); /* Not really used by us, but lets do it anyway */ self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0; @@ -504,7 +504,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) return; } - if ((tty->count == 1) && (self->open_count != 1)) { + if ((tty->count == 1) && (self->port.count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. state->count should always @@ -514,16 +514,16 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) */ IRDA_DEBUG(0, "%s(), bad serial port count; " "tty->count is 1, state->count is %d\n", __func__ , - self->open_count); - self->open_count = 1; + self->port.count); + self->port.count = 1; } - if (--self->open_count < 0) { + if (--self->port.count < 0) { IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n", - __func__, self->line, self->open_count); - self->open_count = 0; + __func__, self->line, self->port.count); + self->port.count = 0; } - if (self->open_count) { + if (self->port.count) { spin_unlock_irqrestore(&self->spinlock, flags); IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ ); @@ -555,7 +555,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) tty->closing = 0; self->tty = NULL; - if (self->blocked_open) { + if (self->port.blocked_open) { if (self->port.close_delay) schedule_timeout_interruptible(self->port.close_delay); wake_up_interruptible(&self->port.open_wait); @@ -1007,7 +1007,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty) spin_lock_irqsave(&self->spinlock, flags); self->flags &= ~ASYNC_NORMAL_ACTIVE; self->tty = NULL; - self->open_count = 0; + self->port.count = 0; spin_unlock_irqrestore(&self->spinlock, flags); wake_up_interruptible(&self->port.open_wait); @@ -1354,7 +1354,7 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_putc(m, '\n'); seq_printf(m, "Role: %s\n", self->client ? "client" : "server"); - seq_printf(m, "Open count: %d\n", self->open_count); + seq_printf(m, "Open count: %d\n", self->port.count); seq_printf(m, "Max data size: %d\n", self->max_data_size); seq_printf(m, "Max header size: %d\n", self->max_header_size); -- cgit v0.10.2 From 849d5a997fe6a9e44401daed62a98121390ec0d3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:19 +0200 Subject: TTY: ircomm, use flags from tty_port Switch to tty_port->flags. And while at it, remove redefined flags for them. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index 5e94bad..e4db3b5 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -52,11 +52,6 @@ /* Same for payload size. See qos.c for the smallest max data size */ #define IRCOMM_TTY_DATA_UNINITIALISED (64 - IRCOMM_TTY_HDR_UNINITIALISED) -/* Those are really defined in include/linux/serial.h - Jean II */ -#define ASYNC_B_INITIALIZED 31 /* Serial port was initialized */ -#define ASYNC_B_NORMAL_ACTIVE 29 /* Normal device is active */ -#define ASYNC_B_CLOSING 27 /* Serial port is closing */ - /* * IrCOMM TTY driver state */ @@ -81,7 +76,6 @@ struct ircomm_tty_cb { LOCAL_FLOW flow; /* IrTTP flow status */ int line; - unsigned long flags; __u8 dlsap_sel; __u8 slsap_sel; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 787578f..8e61026 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -194,7 +194,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self) IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); /* Check if already open */ - if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) { + if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) { IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ ); return 0; } @@ -231,7 +231,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self) return 0; err: - clear_bit(ASYNC_B_INITIALIZED, &self->flags); + clear_bit(ASYNCB_INITIALIZED, &self->port.flags); return ret; } @@ -260,7 +260,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, */ if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - self->flags |= ASYNC_NORMAL_ACTIVE; + self->port.flags |= ASYNC_NORMAL_ACTIVE; IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ ); return 0; } @@ -306,8 +306,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || - !test_bit(ASYNC_B_INITIALIZED, &self->flags)) { - retval = (self->flags & ASYNC_HUP_NOTIFY) ? + !test_bit(ASYNCB_INITIALIZED, &self->port.flags)) { + retval = (self->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } @@ -317,7 +317,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, * specified, we cannot return before the IrCOMM link is * ready */ - if (!test_bit(ASYNC_B_CLOSING, &self->flags) && + if (!test_bit(ASYNCB_CLOSING, &self->port.flags) && (do_clocal || (self->settings.dce & IRCOMM_CD)) && self->state == IRCOMM_TTY_READY) { @@ -350,7 +350,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, __FILE__, __LINE__, tty->driver->name, self->port.count); if (!retval) - self->flags |= ASYNC_NORMAL_ACTIVE; + self->port.flags |= ASYNC_NORMAL_ACTIVE; return retval; } @@ -420,13 +420,13 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) self->line, self->port.count); /* Not really used by us, but lets do it anyway */ - self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || - test_bit(ASYNC_B_CLOSING, &self->flags)) { + test_bit(ASYNCB_CLOSING, &self->port.flags)) { /* Hm, why are we blocking on ASYNC_CLOSING if we * do return -EAGAIN/-ERESTARTSYS below anyway? @@ -437,14 +437,14 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) */ if (wait_event_interruptible(self->port.close_wait, - !test_bit(ASYNC_B_CLOSING, &self->flags))) { + !test_bit(ASYNCB_CLOSING, &self->port.flags))) { IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n", __func__); return -ERESTARTSYS; } #ifdef SERIAL_DO_RESTART - return (self->flags & ASYNC_HUP_NOTIFY) ? + return (self->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; #else return -EAGAIN; @@ -531,7 +531,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) } /* Hum... Should be test_and_set_bit ??? - Jean II */ - set_bit(ASYNC_B_CLOSING, &self->flags); + set_bit(ASYNCB_CLOSING, &self->port.flags); /* We need to unlock here (we were unlocking at the end of this * function), because tty_wait_until_sent() may schedule. @@ -561,7 +561,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&self->port.open_wait); } - self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + self->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&self->port.close_wait); } @@ -954,7 +954,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self) IRDA_DEBUG(0, "%s()\n", __func__ ); - if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags)) + if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags)) return; ircomm_tty_detach_cable(self); @@ -1005,7 +1005,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty) /* I guess we need to lock here - Jean II */ spin_lock_irqsave(&self->spinlock, flags); - self->flags &= ~ASYNC_NORMAL_ACTIVE; + self->port.flags &= ~ASYNC_NORMAL_ACTIVE; self->tty = NULL; self->port.count = 0; spin_unlock_irqrestore(&self->spinlock, flags); @@ -1077,7 +1077,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) if (status & IRCOMM_DCE_DELTA_ANY) { /*wake_up_interruptible(&self->delta_msr_wait);*/ } - if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) { + if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) { IRDA_DEBUG(2, "%s(), ircomm%d CD now %s...\n", __func__ , self->line, (status & IRCOMM_CD) ? "on" : "off"); @@ -1094,7 +1094,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) return; } } - if (self->flags & ASYNC_CTS_FLOW) { + if (self->port.flags & ASYNC_CTS_FLOW) { if (tty->hw_stopped) { if (status & IRCOMM_CTS) { IRDA_DEBUG(2, @@ -1327,27 +1327,27 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_puts(m, "Flags:"); sep = ' '; - if (self->flags & ASYNC_CTS_FLOW) { + if (self->port.flags & ASYNC_CTS_FLOW) { seq_printf(m, "%cASYNC_CTS_FLOW", sep); sep = '|'; } - if (self->flags & ASYNC_CHECK_CD) { + if (self->port.flags & ASYNC_CHECK_CD) { seq_printf(m, "%cASYNC_CHECK_CD", sep); sep = '|'; } - if (self->flags & ASYNC_INITIALIZED) { + if (self->port.flags & ASYNC_INITIALIZED) { seq_printf(m, "%cASYNC_INITIALIZED", sep); sep = '|'; } - if (self->flags & ASYNC_LOW_LATENCY) { + if (self->port.flags & ASYNC_LOW_LATENCY) { seq_printf(m, "%cASYNC_LOW_LATENCY", sep); sep = '|'; } - if (self->flags & ASYNC_CLOSING) { + if (self->port.flags & ASYNC_CLOSING) { seq_printf(m, "%cASYNC_CLOSING", sep); sep = '|'; } - if (self->flags & ASYNC_NORMAL_ACTIVE) { + if (self->port.flags & ASYNC_NORMAL_ACTIVE) { seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep); sep = '|'; } diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index bb1e935..bed311a 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -566,7 +566,8 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self) * will have to wait for the peer device (DCE) to raise the CTS * line. */ - if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) { + if ((self->port.flags & ASYNC_CTS_FLOW) && + ((self->settings.dce & IRCOMM_CTS) == 0)) { IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ ); return; } else { @@ -977,7 +978,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); ircomm_tty_start_watchdog_timer(self, 3*HZ); - if (self->flags & ASYNC_CHECK_CD) { + if (self->port.flags & ASYNC_CHECK_CD) { /* Drop carrier */ self->settings.dce = IRCOMM_DELTA_CD; ircomm_tty_check_modem_status(self); diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index a6d25e3..31b917e 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -90,19 +90,19 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self) /* CTS flow control flag and modem status interrupts */ if (cflag & CRTSCTS) { - self->flags |= ASYNC_CTS_FLOW; + self->port.flags |= ASYNC_CTS_FLOW; self->settings.flow_control |= IRCOMM_RTS_CTS_IN; /* This got me. Bummer. Jean II */ if (self->service_type == IRCOMM_3_WIRE_RAW) IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__); } else { - self->flags &= ~ASYNC_CTS_FLOW; + self->port.flags &= ~ASYNC_CTS_FLOW; self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN; } if (cflag & CLOCAL) - self->flags &= ~ASYNC_CHECK_CD; + self->port.flags &= ~ASYNC_CHECK_CD; else - self->flags |= ASYNC_CHECK_CD; + self->port.flags |= ASYNC_CHECK_CD; #if 0 /* * Set up parity check flag @@ -270,7 +270,7 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self, memset(&info, 0, sizeof(info)); info.line = self->line; - info.flags = self->flags; + info.flags = self->port.flags; info.baud_base = self->settings.data_rate; info.close_delay = self->port.close_delay; info.closing_wait = self->port.closing_wait; -- cgit v0.10.2 From e673927d8a210ab1db27047080fc1bdb47f7e372 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:20 +0200 Subject: TTY: ircomm, revamp locking Use self->spinlock only for ctrl_skb and tx_skb. TTY stuff is now protected by tty_port->lock. This is needed for further cleanup (and conversion to tty_port helpers). This also closes the race in the end of close. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index e4db3b5..a9027d8 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -96,7 +96,6 @@ struct ircomm_tty_cb { struct work_struct tqueue; /* Protect concurent access to : - * o self->open_count * o self->ctrl_skb * o self->tx_skb * Maybe other things may gain to be protected as well... diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 8e61026..7b2152c 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -283,13 +283,12 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n", __FILE__, __LINE__, tty->driver->name, self->port.count); - /* As far as I can see, we protect port.count - Jean II */ - spin_lock_irqsave(&self->spinlock, flags); + spin_lock_irqsave(&self->port.lock, flags); if (!tty_hung_up_p(filp)) { extra_count = 1; self->port.count--; } - spin_unlock_irqrestore(&self->spinlock, flags); + spin_unlock_irqrestore(&self->port.lock, flags); self->port.blocked_open++; while (1) { @@ -340,9 +339,9 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, if (extra_count) { /* ++ is not atomic, so this should be protected - Jean II */ - spin_lock_irqsave(&self->spinlock, flags); + spin_lock_irqsave(&self->port.lock, flags); self->port.count++; - spin_unlock_irqrestore(&self->spinlock, flags); + spin_unlock_irqrestore(&self->port.lock, flags); } self->port.blocked_open--; @@ -409,12 +408,12 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); } /* ++ is not atomic, so this should be protected - Jean II */ - spin_lock_irqsave(&self->spinlock, flags); + spin_lock_irqsave(&self->port.lock, flags); self->port.count++; tty->driver_data = self; self->tty = tty; - spin_unlock_irqrestore(&self->spinlock, flags); + spin_unlock_irqrestore(&self->port.lock, flags); IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name, self->line, self->port.count); @@ -495,10 +494,10 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - spin_lock_irqsave(&self->spinlock, flags); + spin_lock_irqsave(&self->port.lock, flags); if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&self->spinlock, flags); + spin_unlock_irqrestore(&self->port.lock, flags); IRDA_DEBUG(0, "%s(), returning 1\n", __func__ ); return; @@ -524,20 +523,15 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) self->port.count = 0; } if (self->port.count) { - spin_unlock_irqrestore(&self->spinlock, flags); + spin_unlock_irqrestore(&self->port.lock, flags); IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ ); return; } - /* Hum... Should be test_and_set_bit ??? - Jean II */ set_bit(ASYNCB_CLOSING, &self->port.flags); - /* We need to unlock here (we were unlocking at the end of this - * function), because tty_wait_until_sent() may schedule. - * I don't know if the rest should be protected somehow, - * so someone should check. - Jean II */ - spin_unlock_irqrestore(&self->spinlock, flags); + spin_unlock_irqrestore(&self->port.lock, flags); /* * Now we wait for the transmit buffer to clear; and we notify @@ -552,16 +546,21 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) tty_driver_flush_buffer(tty); tty_ldisc_flush(tty); + spin_lock_irqsave(&self->port.lock, flags); tty->closing = 0; self->tty = NULL; if (self->port.blocked_open) { - if (self->port.close_delay) + if (self->port.close_delay) { + spin_unlock_irqrestore(&self->port.lock, flags); schedule_timeout_interruptible(self->port.close_delay); + spin_lock_irqsave(&self->port.lock, flags); + } wake_up_interruptible(&self->port.open_wait); } self->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + spin_unlock_irqrestore(&self->port.lock, flags); wake_up_interruptible(&self->port.close_wait); } @@ -1003,12 +1002,11 @@ static void ircomm_tty_hangup(struct tty_struct *tty) /* ircomm_tty_flush_buffer(tty); */ ircomm_tty_shutdown(self); - /* I guess we need to lock here - Jean II */ - spin_lock_irqsave(&self->spinlock, flags); + spin_lock_irqsave(&self->port.lock, flags); self->port.flags &= ~ASYNC_NORMAL_ACTIVE; self->tty = NULL; self->port.count = 0; - spin_unlock_irqrestore(&self->spinlock, flags); + spin_unlock_irqrestore(&self->port.lock, flags); wake_up_interruptible(&self->port.open_wait); } -- cgit v0.10.2 From 62f228acb807c370c3b1583bf0f1aa4ab8e19aca Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:21 +0200 Subject: TTY: ircomm, use tty from tty_port This also includes a switch to tty refcounting. It makes sure, the code no longer can access a freed TTY struct. Sometimes the only thing needed is to pass tty down to the callies. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h index a9027d8..80ffde3 100644 --- a/include/net/irda/ircomm_tty.h +++ b/include/net/irda/ircomm_tty.h @@ -62,7 +62,6 @@ struct ircomm_tty_cb { int state; /* Connect state */ - struct tty_struct *tty; struct ircomm_cb *ircomm; /* IrCOMM layer instance */ struct sk_buff *tx_skb; /* Transmit buffer */ diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c index 8b915f3..3089391 100644 --- a/net/irda/ircomm/ircomm_param.c +++ b/net/irda/ircomm/ircomm_param.c @@ -99,7 +99,6 @@ pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 }; */ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) { - struct tty_struct *tty; unsigned long flags; struct sk_buff *skb; int count; @@ -109,10 +108,6 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - tty = self->tty; - if (!tty) - return 0; - /* Make sure we don't send parameters for raw mode */ if (self->service_type == IRCOMM_3_WIRE_RAW) return 0; diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 7b2152c..03acc07 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -242,18 +242,15 @@ err: * */ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, - struct file *filp) + struct tty_struct *tty, struct file *filp) { DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0, extra_count = 0; unsigned long flags; - struct tty_struct *tty; IRDA_DEBUG(2, "%s()\n", __func__ ); - tty = self->tty; - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -412,8 +409,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) self->port.count++; tty->driver_data = self; - self->tty = tty; spin_unlock_irqrestore(&self->port.lock, flags); + tty_port_tty_set(&self->port, tty); IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name, self->line, self->port.count); @@ -467,7 +464,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) if (ret) return ret; - ret = ircomm_tty_block_til_ready(self, filp); + ret = ircomm_tty_block_til_ready(self, tty, filp); if (ret) { IRDA_DEBUG(2, "%s(), returning after block_til_ready with %d\n", __func__ , @@ -548,7 +545,6 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&self->port.lock, flags); tty->closing = 0; - self->tty = NULL; if (self->port.blocked_open) { if (self->port.close_delay) { @@ -562,6 +558,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) self->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); spin_unlock_irqrestore(&self->port.lock, flags); wake_up_interruptible(&self->port.close_wait); + tty_port_tty_set(&self->port, NULL); } /* @@ -604,7 +601,7 @@ static void ircomm_tty_do_softint(struct work_struct *work) if (!self || self->magic != IRCOMM_TTY_MAGIC) return; - tty = self->tty; + tty = tty_port_tty_get(&self->port); if (!tty) return; @@ -625,7 +622,7 @@ static void ircomm_tty_do_softint(struct work_struct *work) } if (tty->hw_stopped) - return; + goto put; /* Unlink transmit buffer */ spin_lock_irqsave(&self->spinlock, flags); @@ -644,6 +641,8 @@ static void ircomm_tty_do_softint(struct work_struct *work) /* Check if user (still) wants to be waken up */ tty_wakeup(tty); +put: + tty_kref_put(tty); } /* @@ -1004,7 +1003,11 @@ static void ircomm_tty_hangup(struct tty_struct *tty) spin_lock_irqsave(&self->port.lock, flags); self->port.flags &= ~ASYNC_NORMAL_ACTIVE; - self->tty = NULL; + if (self->port.tty) { + set_bit(TTY_IO_ERROR, &self->port.tty->flags); + tty_kref_put(self->port.tty); + } + self->port.tty = NULL; self->port.count = 0; spin_unlock_irqrestore(&self->port.lock, flags); @@ -1068,7 +1071,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - tty = self->tty; + tty = tty_port_tty_get(&self->port); status = self->settings.dce; @@ -1089,10 +1092,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) tty_hangup(tty); /* Hangup will remote the tty, so better break out */ - return; + goto put; } } - if (self->port.flags & ASYNC_CTS_FLOW) { + if (tty && self->port.flags & ASYNC_CTS_FLOW) { if (tty->hw_stopped) { if (status & IRCOMM_CTS) { IRDA_DEBUG(2, @@ -1103,7 +1106,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) wake_up_interruptible(&self->port.open_wait); schedule_work(&self->tqueue); - return; + goto put; } } else { if (!(status & IRCOMM_CTS)) { @@ -1113,6 +1116,8 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) } } } +put: + tty_kref_put(tty); } /* @@ -1125,6 +1130,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap, struct sk_buff *skb) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + struct tty_struct *tty; IRDA_DEBUG(2, "%s()\n", __func__ ); @@ -1132,7 +1138,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap, IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); IRDA_ASSERT(skb != NULL, return -1;); - if (!self->tty) { + tty = tty_port_tty_get(&self->port); + if (!tty) { IRDA_DEBUG(0, "%s(), no tty!\n", __func__ ); return 0; } @@ -1143,7 +1150,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap, * Devices like WinCE can do this, and since they don't send any * params, we can just as well declare the hardware for running. */ - if (self->tty->hw_stopped && (self->flow == FLOW_START)) { + if (tty->hw_stopped && (self->flow == FLOW_START)) { IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ ); ircomm_param_request(self, IRCOMM_POLL, TRUE); @@ -1156,8 +1163,9 @@ static int ircomm_tty_data_indication(void *instance, void *sap, * Use flip buffer functions since the code may be called from interrupt * context */ - tty_insert_flip_string(self->tty, skb->data, skb->len); - tty_flip_buffer_push(self->tty); + tty_insert_flip_string(tty, skb->data, skb->len); + tty_flip_buffer_push(tty); + tty_kref_put(tty); /* No need to kfree_skb - see ircomm_ttp_data_indication() */ @@ -1208,12 +1216,13 @@ static void ircomm_tty_flow_indication(void *instance, void *sap, IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - tty = self->tty; + tty = tty_port_tty_get(&self->port); switch (cmd) { case FLOW_START: IRDA_DEBUG(2, "%s(), hw start!\n", __func__ ); - tty->hw_stopped = 0; + if (tty) + tty->hw_stopped = 0; /* ircomm_tty_do_softint will take care of the rest */ schedule_work(&self->tqueue); @@ -1221,15 +1230,19 @@ static void ircomm_tty_flow_indication(void *instance, void *sap, default: /* If we get here, something is very wrong, better stop */ case FLOW_STOP: IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ ); - tty->hw_stopped = 1; + if (tty) + tty->hw_stopped = 1; break; } + + tty_kref_put(tty); self->flow = cmd; } #ifdef CONFIG_PROC_FS static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) { + struct tty_struct *tty; char sep; seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]); @@ -1356,9 +1369,12 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_printf(m, "Max data size: %d\n", self->max_data_size); seq_printf(m, "Max header size: %d\n", self->max_header_size); - if (self->tty) + tty = tty_port_tty_get(&self->port); + if (tty) { seq_printf(m, "Hardware: %s\n", - self->tty->hw_stopped ? "Stopped" : "Running"); + tty->hw_stopped ? "Stopped" : "Running"); + tty_kref_put(tty); + } } static int ircomm_tty_proc_show(struct seq_file *m, void *v) diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index bed311a..3ab70e7 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -130,6 +130,8 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, */ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self) { + struct tty_struct *tty; + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -142,7 +144,11 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self) } /* Make sure nobody tries to write before the link is up */ - self->tty->hw_stopped = 1; + tty = tty_port_tty_get(&self->port); + if (tty) { + tty->hw_stopped = 1; + tty_kref_put(tty); + } ircomm_tty_ias_register(self); @@ -398,23 +404,26 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap, struct sk_buff *skb) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; + struct tty_struct *tty; IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - if (!self->tty) + tty = tty_port_tty_get(&self->port); + if (!tty) return; /* This will stop control data transfers */ self->flow = FLOW_STOP; /* Stop data transfers */ - self->tty->hw_stopped = 1; + tty->hw_stopped = 1; ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL, NULL); + tty_kref_put(tty); } /* @@ -550,12 +559,15 @@ void ircomm_tty_connect_indication(void *instance, void *sap, */ void ircomm_tty_link_established(struct ircomm_tty_cb *self) { + struct tty_struct *tty; + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - if (!self->tty) + tty = tty_port_tty_get(&self->port); + if (!tty) return; del_timer(&self->watchdog_timer); @@ -569,17 +581,19 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self) if ((self->port.flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) { IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ ); - return; + goto put; } else { IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ ); - self->tty->hw_stopped = 0; + tty->hw_stopped = 0; /* Wake up processes blocked on open */ wake_up_interruptible(&self->port.open_wait); } schedule_work(&self->tqueue); +put: + tty_kref_put(tty); } /* @@ -983,9 +997,12 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, self->settings.dce = IRCOMM_DELTA_CD; ircomm_tty_check_modem_status(self); } else { + struct tty_struct *tty = tty_port_tty_get(&self->port); IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ ); - if (self->tty) - tty_hangup(self->tty); + if (tty) { + tty_hangup(tty); + tty_kref_put(tty); + } } break; default: diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 31b917e..0eab650 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -52,17 +52,18 @@ * Change speed of the driver. If the remote device is a DCE, then this * should make it change the speed of its serial port */ -static void ircomm_tty_change_speed(struct ircomm_tty_cb *self) +static void ircomm_tty_change_speed(struct ircomm_tty_cb *self, + struct tty_struct *tty) { unsigned int cflag, cval; int baud; IRDA_DEBUG(2, "%s()\n", __func__ ); - if (!self->tty || !self->tty->termios || !self->ircomm) + if (!self->ircomm) return; - cflag = self->tty->termios->c_cflag; + cflag = tty->termios->c_cflag; /* byte size and parity */ switch (cflag & CSIZE) { @@ -81,7 +82,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self) cval |= IRCOMM_PARITY_EVEN; /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(self->tty); + baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ @@ -159,7 +160,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty, return; } - ircomm_tty_change_speed(self); + ircomm_tty_change_speed(self, tty); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && -- cgit v0.10.2 From 38c58032f07be4dee764baa573b233e9a828c119 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:22 +0200 Subject: TTY: ircomm, define local tty_port In some functions we use tty_port heavily. So let us have a local pointer to that variable instead of having self->port all over the code. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 03acc07..199d9cb 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -244,6 +244,7 @@ err: static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, struct tty_struct *tty, struct file *filp) { + struct tty_port *port = &self->port; DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0, extra_count = 0; @@ -257,7 +258,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, */ if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - self->port.flags |= ASYNC_NORMAL_ACTIVE; + port->flags |= ASYNC_NORMAL_ACTIVE; IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ ); return 0; } @@ -269,24 +270,24 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in - * this loop, self->port.count is dropped by one, so that + * this loop, port->count is dropped by one, so that * mgsl_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; - add_wait_queue(&self->port.open_wait, &wait); + add_wait_queue(&port->open_wait, &wait); IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n", - __FILE__, __LINE__, tty->driver->name, self->port.count); + __FILE__, __LINE__, tty->driver->name, port->count); - spin_lock_irqsave(&self->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) { extra_count = 1; - self->port.count--; + port->count--; } - spin_unlock_irqrestore(&self->port.lock, flags); - self->port.blocked_open++; + spin_unlock_irqrestore(&port->lock, flags); + port->blocked_open++; while (1) { if (tty->termios->c_cflag & CBAUD) { @@ -302,8 +303,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || - !test_bit(ASYNCB_INITIALIZED, &self->port.flags)) { - retval = (self->port.flags & ASYNC_HUP_NOTIFY) ? + !test_bit(ASYNCB_INITIALIZED, &port->flags)) { + retval = (port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS; break; } @@ -313,7 +314,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, * specified, we cannot return before the IrCOMM link is * ready */ - if (!test_bit(ASYNCB_CLOSING, &self->port.flags) && + if (!test_bit(ASYNCB_CLOSING, &port->flags) && (do_clocal || (self->settings.dce & IRCOMM_CD)) && self->state == IRCOMM_TTY_READY) { @@ -326,27 +327,27 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, } IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n", - __FILE__, __LINE__, tty->driver->name, self->port.count); + __FILE__, __LINE__, tty->driver->name, port->count); schedule(); } __set_current_state(TASK_RUNNING); - remove_wait_queue(&self->port.open_wait, &wait); + remove_wait_queue(&port->open_wait, &wait); if (extra_count) { /* ++ is not atomic, so this should be protected - Jean II */ - spin_lock_irqsave(&self->port.lock, flags); - self->port.count++; - spin_unlock_irqrestore(&self->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); + port->count++; + spin_unlock_irqrestore(&port->lock, flags); } - self->port.blocked_open--; + port->blocked_open--; IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n", - __FILE__, __LINE__, tty->driver->name, self->port.count); + __FILE__, __LINE__, tty->driver->name, port->count); if (!retval) - self->port.flags |= ASYNC_NORMAL_ACTIVE; + port->flags |= ASYNC_NORMAL_ACTIVE; return retval; } @@ -484,6 +485,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + struct tty_port *port = &self->port; unsigned long flags; IRDA_DEBUG(0, "%s()\n", __func__ ); @@ -491,16 +493,16 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - spin_lock_irqsave(&self->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&self->port.lock, flags); + spin_unlock_irqrestore(&port->lock, flags); IRDA_DEBUG(0, "%s(), returning 1\n", __func__ ); return; } - if ((tty->count == 1) && (self->port.count != 1)) { + if ((tty->count == 1) && (port->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. state->count should always @@ -510,55 +512,55 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) */ IRDA_DEBUG(0, "%s(), bad serial port count; " "tty->count is 1, state->count is %d\n", __func__ , - self->port.count); - self->port.count = 1; + port->count); + port->count = 1; } - if (--self->port.count < 0) { + if (--port->count < 0) { IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n", - __func__, self->line, self->port.count); - self->port.count = 0; + __func__, self->line, port->count); + port->count = 0; } - if (self->port.count) { - spin_unlock_irqrestore(&self->port.lock, flags); + if (port->count) { + spin_unlock_irqrestore(&port->lock, flags); IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ ); return; } - set_bit(ASYNCB_CLOSING, &self->port.flags); + set_bit(ASYNCB_CLOSING, &port->flags); - spin_unlock_irqrestore(&self->port.lock, flags); + spin_unlock_irqrestore(&port->lock, flags); /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (self->port.closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent_from_close(tty, self->port.closing_wait); + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent_from_close(tty, port->closing_wait); ircomm_tty_shutdown(self); tty_driver_flush_buffer(tty); tty_ldisc_flush(tty); - spin_lock_irqsave(&self->port.lock, flags); + spin_lock_irqsave(&port->lock, flags); tty->closing = 0; - if (self->port.blocked_open) { - if (self->port.close_delay) { - spin_unlock_irqrestore(&self->port.lock, flags); - schedule_timeout_interruptible(self->port.close_delay); - spin_lock_irqsave(&self->port.lock, flags); + if (port->blocked_open) { + if (port->close_delay) { + spin_unlock_irqrestore(&port->lock, flags); + schedule_timeout_interruptible(port->close_delay); + spin_lock_irqsave(&port->lock, flags); } - wake_up_interruptible(&self->port.open_wait); + wake_up_interruptible(&port->open_wait); } - self->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - spin_unlock_irqrestore(&self->port.lock, flags); - wake_up_interruptible(&self->port.close_wait); - tty_port_tty_set(&self->port, NULL); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + spin_unlock_irqrestore(&port->lock, flags); + wake_up_interruptible(&port->close_wait); + tty_port_tty_set(port, NULL); } /* @@ -991,6 +993,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self) static void ircomm_tty_hangup(struct tty_struct *tty) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; + struct tty_port *port = &self->port; unsigned long flags; IRDA_DEBUG(0, "%s()\n", __func__ ); @@ -1001,17 +1004,17 @@ static void ircomm_tty_hangup(struct tty_struct *tty) /* ircomm_tty_flush_buffer(tty); */ ircomm_tty_shutdown(self); - spin_lock_irqsave(&self->port.lock, flags); - self->port.flags &= ~ASYNC_NORMAL_ACTIVE; - if (self->port.tty) { - set_bit(TTY_IO_ERROR, &self->port.tty->flags); - tty_kref_put(self->port.tty); + spin_lock_irqsave(&port->lock, flags); + port->flags &= ~ASYNC_NORMAL_ACTIVE; + if (port->tty) { + set_bit(TTY_IO_ERROR, &port->tty->flags); + tty_kref_put(port->tty); } - self->port.tty = NULL; - self->port.count = 0; - spin_unlock_irqrestore(&self->port.lock, flags); + port->tty = NULL; + port->count = 0; + spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&self->port.open_wait); + wake_up_interruptible(&port->open_wait); } /* -- cgit v0.10.2 From 0ba9ff846b2f4720e30ace37b028ef14fb97fb74 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:23 +0200 Subject: TTY: ircomm, define carrier routines These will be used by the tty_port wait_til_ready later. (Now they are used by our code.) Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 199d9cb..3fdce18 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -104,6 +104,35 @@ static const struct tty_operations ops = { #endif /* CONFIG_PROC_FS */ }; +static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise) +{ + struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb, + port); + /* + * Here, we use to lock those two guys, but as ircomm_param_request() + * does it itself, I don't see the point (and I see the deadlock). + * Jean II + */ + if (raise) + self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR; + else + self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR); + + ircomm_param_request(self, IRCOMM_DTE, TRUE); +} + +static int ircomm_port_carrier_raised(struct tty_port *port) +{ + struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb, + port); + return self->settings.dce & IRCOMM_CD; +} + +static const struct tty_port_operations ircomm_port_ops = { + .dtr_rts = ircomm_port_raise_dtr_rts, + .carrier_raised = ircomm_port_carrier_raised, +}; + /* * Function ircomm_tty_init() * @@ -290,15 +319,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, port->blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) { - /* Here, we use to lock those two guys, but - * as ircomm_param_request() does it itself, - * I don't see the point (and I see the deadlock). - * Jean II */ - self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR; - - ircomm_param_request(self, IRCOMM_DTE, TRUE); - } + if (tty->termios->c_cflag & CBAUD) + tty_port_raise_dtr_rts(port); current->state = TASK_INTERRUPTIBLE; @@ -315,7 +337,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, * ready */ if (!test_bit(ASYNCB_CLOSING, &port->flags) && - (do_clocal || (self->settings.dce & IRCOMM_CD)) && + (do_clocal || tty_port_carrier_raised(port)) && self->state == IRCOMM_TTY_READY) { break; @@ -379,6 +401,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) } tty_port_init(&self->port); + self->port.ops = &ircomm_port_ops; self->magic = IRCOMM_TTY_MAGIC; self->flow = FLOW_STOP; -- cgit v0.10.2 From a1e844036af9cb0d87e878a4f90ce64713c76e5a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:24 +0200 Subject: TTY: ircomm, use tty_port_close_end helper Again, the code is identical, so leverage the helper code. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 3fdce18..cfe352d 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -568,21 +568,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) tty_driver_flush_buffer(tty); tty_ldisc_flush(tty); - spin_lock_irqsave(&port->lock, flags); - tty->closing = 0; - - if (port->blocked_open) { - if (port->close_delay) { - spin_unlock_irqrestore(&port->lock, flags); - schedule_timeout_interruptible(port->close_delay); - spin_lock_irqsave(&port->lock, flags); - } - wake_up_interruptible(&port->open_wait); - } - - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&port->close_wait); + tty_port_close_end(port, tty); tty_port_tty_set(port, NULL); } -- cgit v0.10.2 From c0e7865003ae9929f32bcb7277f591115fa242b7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:25 +0200 Subject: TTY: ircomm, use tty_port_close_start helper Again, the code is identical, so leverage the helper code. Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Cc: netdev@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index cfe352d..4e35b45 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -509,64 +509,18 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; struct tty_port *port = &self->port; - unsigned long flags; IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - spin_lock_irqsave(&port->lock, flags); - - if (tty_hung_up_p(filp)) { - spin_unlock_irqrestore(&port->lock, flags); - - IRDA_DEBUG(0, "%s(), returning 1\n", __func__ ); - return; - } - - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - IRDA_DEBUG(0, "%s(), bad serial port count; " - "tty->count is 1, state->count is %d\n", __func__ , - port->count); - port->count = 1; - } - - if (--port->count < 0) { - IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n", - __func__, self->line, port->count); - port->count = 0; - } - if (port->count) { - spin_unlock_irqrestore(&port->lock, flags); - - IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ ); + if (tty_port_close_start(port, tty, filp) == 0) return; - } - - set_bit(ASYNCB_CLOSING, &port->flags); - - spin_unlock_irqrestore(&port->lock, flags); - - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent_from_close(tty, port->closing_wait); ircomm_tty_shutdown(self); tty_driver_flush_buffer(tty); - tty_ldisc_flush(tty); tty_port_close_end(port, tty); tty_port_tty_set(port, NULL); -- cgit v0.10.2 From 042e6c29c16c9c20c31110b611ed60187b0c873a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:26 +0200 Subject: TTY: um/line, add tty_port And use count from there. Signed-off-by: Jiri Slaby Cc: Jeff Dike Cc: Richard Weinberger Cc: user-mode-linux-devel@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index acfd0e0..482a7bd 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -404,7 +404,7 @@ int line_open(struct line *lines, struct tty_struct *tty) goto out_unlock; err = 0; - if (line->count++) + if (line->port.count++) goto out_unlock; BUG_ON(tty->driver_data); @@ -446,7 +446,7 @@ void line_close(struct tty_struct *tty, struct file * filp) mutex_lock(&line->count_lock); BUG_ON(!line->valid); - if (--line->count) + if (--line->port.count) goto out_unlock; line->tty = NULL; @@ -478,7 +478,7 @@ int setup_one_line(struct line *lines, int n, char *init, mutex_lock(&line->count_lock); - if (line->count) { + if (line->port.count) { *error_out = "Device is already open"; goto out; } @@ -663,6 +663,7 @@ int register_lines(struct line_driver *line_driver, driver->init_termios = tty_std_termios; for (i = 0; i < nlines; i++) { + tty_port_init(&lines[i].port); spin_lock_init(&lines[i].lock); mutex_init(&lines[i].count_lock); lines[i].driver = line_driver; diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index 0a18347..0e06a1f 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -32,9 +32,9 @@ struct line_driver { }; struct line { + struct tty_port port; struct tty_struct *tty; struct mutex count_lock; - unsigned long count; int valid; char *init_str; -- cgit v0.10.2 From 95f4d5f01bb56b4f940c8b44be8e71c5f35f2069 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:27 +0200 Subject: TTY: um/line, use tty from tty_port This means switching to the tty refcounted model so that we will not race with interrupts. Signed-off-by: Jiri Slaby Cc: Jeff Dike Cc: Richard Weinberger Cc: user-mode-linux-devel@lists.sourceforge.net Signed-off-by: Greg Kroah-Hartman diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 45e248c..87eebfe 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -150,9 +150,11 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty) static void line_timer_cb(struct work_struct *work) { struct line *line = container_of(work, struct line, task.work); + struct tty_struct *tty = tty_port_tty_get(&line->port); if (!line->throttled) - chan_interrupt(line, line->tty, line->driver->read_irq); + chan_interrupt(line, tty, line->driver->read_irq); + tty_kref_put(tty); } int enable_chan(struct line *line) diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 482a7bd..fb6e4ea 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -19,9 +19,11 @@ static irqreturn_t line_interrupt(int irq, void *data) { struct chan *chan = data; struct line *line = chan->line; + struct tty_struct *tty = tty_port_tty_get(&line->port); if (line) - chan_interrupt(line, line->tty, irq); + chan_interrupt(line, tty, irq); + tty_kref_put(tty); return IRQ_HANDLED; } @@ -333,7 +335,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data) { struct chan *chan = data; struct line *line = chan->line; - struct tty_struct *tty = line->tty; + struct tty_struct *tty; int err; /* @@ -352,10 +354,13 @@ static irqreturn_t line_write_interrupt(int irq, void *data) } spin_unlock(&line->lock); + tty = tty_port_tty_get(&line->port); if (tty == NULL) return IRQ_NONE; tty_wakeup(tty); + tty_kref_put(tty); + return IRQ_HANDLED; } @@ -409,7 +414,7 @@ int line_open(struct line *lines, struct tty_struct *tty) BUG_ON(tty->driver_data); tty->driver_data = line; - line->tty = tty; + tty_port_tty_set(&line->port, tty); err = enable_chan(line); if (err) /* line_close() will be called by our caller */ @@ -449,7 +454,7 @@ void line_close(struct tty_struct *tty, struct file * filp) if (--line->port.count) goto out_unlock; - line->tty = NULL; + tty_port_tty_set(&line->port, NULL); tty->driver_data = NULL; if (line->sigio) { @@ -610,9 +615,15 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, mutex_lock(&line->count_lock); if (!line->valid) CONFIG_CHUNK(str, size, n, "none", 1); - else if (line->tty == NULL) - CONFIG_CHUNK(str, size, n, line->init_str, 1); - else n = chan_config_string(line, str, size, error_out); + else { + struct tty_struct *tty = tty_port_tty_get(&line->port); + if (tty == NULL) { + CONFIG_CHUNK(str, size, n, line->init_str, 1); + } else { + n = chan_config_string(line, str, size, error_out); + tty_kref_put(tty); + } + } mutex_unlock(&line->count_lock); return n; diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index 0e06a1f..5b3d4fb 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -33,7 +33,6 @@ struct line_driver { struct line { struct tty_port port; - struct tty_struct *tty; struct mutex count_lock; int valid; -- cgit v0.10.2 From 9800ee6f50a3b94181d4df57542b9379e331decb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 13 Jun 2012 00:28:23 +0200 Subject: serial: sh-sci: Fix probe error paths When probing fails, the driver must not try to cleanup resources that have not been initialized. Fix this. Signed-off-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 4604153..27df2ad 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2179,6 +2179,16 @@ static int __devinit sci_init_single(struct platform_device *dev, return 0; } +static void sci_cleanup_single(struct sci_port *port) +{ + sci_free_gpios(port); + + clk_put(port->iclk); + clk_put(port->fclk); + + pm_runtime_disable(port->port.dev); +} + #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE static void serial_console_putchar(struct uart_port *port, int ch) { @@ -2360,14 +2370,10 @@ static int sci_remove(struct platform_device *dev) cpufreq_unregister_notifier(&port->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); - sci_free_gpios(port); - uart_remove_one_port(&sci_uart_driver, &port->port); - clk_put(port->iclk); - clk_put(port->fclk); + sci_cleanup_single(port); - pm_runtime_disable(&dev->dev); return 0; } @@ -2392,7 +2398,13 @@ static int __devinit sci_probe_single(struct platform_device *dev, if (ret) return ret; - return uart_add_one_port(&sci_uart_driver, &sciport->port); + ret = uart_add_one_port(&sci_uart_driver, &sciport->port); + if (ret) { + sci_cleanup_single(sciport); + return ret; + } + + return 0; } static int __devinit sci_probe(struct platform_device *dev) @@ -2413,24 +2425,22 @@ static int __devinit sci_probe(struct platform_device *dev) ret = sci_probe_single(dev, dev->id, p, sp); if (ret) - goto err_unreg; + return ret; sp->freq_transition.notifier_call = sci_notifier; ret = cpufreq_register_notifier(&sp->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); - if (unlikely(ret < 0)) - goto err_unreg; + if (unlikely(ret < 0)) { + sci_cleanup_single(sp); + return ret; + } #ifdef CONFIG_SH_STANDARD_BIOS sh_bios_gdb_detach(); #endif return 0; - -err_unreg: - sci_remove(dev); - return ret; } static int sci_suspend(struct device *dev) -- cgit v0.10.2 From 8856a7d6b7c39eece126f23c6cdbd11ff2218d6f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 13 Jun 2012 00:28:24 +0200 Subject: serial: sh-sci: Make probe fail for ports that exceed the maximum count The driver supports a maximum number of ports configurable at compile time. Make sure the probe() method fails when registering a port that exceeds the maximum instead of returning success without registering the port. This fixes a crash at system suspend time, when the driver tried to suspend a non-registered port using the UART core. Signed-off-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 27df2ad..1bd9163 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2391,7 +2391,7 @@ static int __devinit sci_probe_single(struct platform_device *dev, index+1, SCI_NPORTS); dev_notice(&dev->dev, "Consider bumping " "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n"); - return 0; + return -EINVAL; } ret = sci_init_single(dev, sciport, index, p); -- cgit v0.10.2 From 7171604ae7b3bbc738b6a4b7cd0ee73eb0d551d9 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:28 +0200 Subject: PTY: remove one empty ops->remove Currently, there are two as a left-over from previous patches. Although we really need to provide an empty handler, we do not need two. So remove one of them. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 5505ffc..4bcaf89 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -557,18 +557,14 @@ err_free_tty: return -ENOMEM; } -static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) -{ -} - -static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) +static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) { } static const struct tty_operations ptm_unix98_ops = { .lookup = ptm_unix98_lookup, .install = pty_unix98_install, - .remove = ptm_unix98_remove, + .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, @@ -585,7 +581,7 @@ static const struct tty_operations ptm_unix98_ops = { static const struct tty_operations pty_unix98_ops = { .lookup = pts_unix98_lookup, .install = pty_unix98_install, - .remove = pts_unix98_remove, + .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, -- cgit v0.10.2 From 5d249bc6a61e7a434c69e0d0becc77a803c8c5e8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:29 +0200 Subject: PTY: merge pty_install implementations There are currently two instances of code which handles PTY install. One for the legacy BSD PTY's, one for unix98's PTY's. Both of them are very similar and differ only in termios allocation and handling. Since we will need to allocate a tty_port at that place, this would require editing two places with the same pattern. Instead, let us move the implementation to one common place and call it from both places. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 4bcaf89..881888f 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -282,39 +282,53 @@ done: return 0; } -/* Traditional BSD devices */ -#ifdef CONFIG_LEGACY_PTYS - -static int pty_install(struct tty_driver *driver, struct tty_struct *tty) +static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, + bool legacy) { struct tty_struct *o_tty; int idx = tty->index; - int retval; + int retval = -ENOMEM; o_tty = alloc_tty_struct(); if (!o_tty) - return -ENOMEM; + goto err; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ - retval = -ENOMEM; goto err_free_tty; } initialize_tty_struct(o_tty, driver->other, idx); - /* We always use new tty termios data so we can do this - the easy way .. */ - retval = tty_init_termios(tty); - if (retval) - goto err_deinit_tty; - - retval = tty_init_termios(o_tty); - if (retval) - goto err_free_termios; + if (legacy) { + /* We always use new tty termios data so we can do this + the easy way .. */ + retval = tty_init_termios(tty); + if (retval) + goto err_deinit_tty; + + retval = tty_init_termios(o_tty); + if (retval) + goto err_free_termios; + + driver->other->ttys[idx] = o_tty; + driver->ttys[idx] = tty; + } else { + tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); + if (tty->termios == NULL) + goto err_deinit_tty; + *tty->termios = driver->init_termios; + tty->termios_locked = tty->termios + 1; + + o_tty->termios = kzalloc(sizeof(struct ktermios[2]), + GFP_KERNEL); + if (o_tty->termios == NULL) + goto err_free_termios; + *o_tty->termios = driver->other->init_termios; + o_tty->termios_locked = o_tty->termios + 1; + } /* * Everything allocated ... set up the o_tty structure. */ - driver->other->ttys[idx] = o_tty; tty_driver_kref_get(driver->other); if (driver->subtype == PTY_TYPE_MASTER) o_tty->count++; @@ -324,18 +338,29 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty) tty_driver_kref_get(driver); tty->count++; - driver->ttys[idx] = tty; return 0; err_free_termios: - tty_free_termios(tty); + if (legacy) + tty_free_termios(tty); + else + kfree(tty->termios); err_deinit_tty: deinitialize_tty_struct(o_tty); module_put(o_tty->driver->owner); err_free_tty: free_tty_struct(o_tty); +err: return retval; } +/* Traditional BSD devices */ +#ifdef CONFIG_LEGACY_PTYS + +static int pty_install(struct tty_driver *driver, struct tty_struct *tty) +{ + return pty_common_install(driver, tty, true); +} + static int pty_bsd_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -509,52 +534,7 @@ static void pty_unix98_shutdown(struct tty_struct *tty) static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) { - struct tty_struct *o_tty; - int idx = tty->index; - - o_tty = alloc_tty_struct(); - if (!o_tty) - return -ENOMEM; - if (!try_module_get(driver->other->owner)) { - /* This cannot in fact currently happen */ - goto err_free_tty; - } - initialize_tty_struct(o_tty, driver->other, idx); - - tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (tty->termios == NULL) - goto err_free_mem; - *tty->termios = driver->init_termios; - tty->termios_locked = tty->termios + 1; - - o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (o_tty->termios == NULL) - goto err_free_mem; - *o_tty->termios = driver->other->init_termios; - o_tty->termios_locked = o_tty->termios + 1; - - tty_driver_kref_get(driver->other); - if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; - /* Establish the links in both directions */ - tty->link = o_tty; - o_tty->link = tty; - /* - * All structures have been allocated, so now we install them. - * Failures after this point use release_tty to clean up, so - * there's no need to null out the local pointers. - */ - tty_driver_kref_get(driver); - tty->count++; - return 0; -err_free_mem: - deinitialize_tty_struct(o_tty); - kfree(o_tty->termios); - kfree(tty->termios); - module_put(o_tty->driver->owner); -err_free_tty: - free_tty_struct(o_tty); - return -ENOMEM; + return pty_common_install(driver, tty, false); } static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) -- cgit v0.10.2 From d03702a27df017d1807fd4809f03adaa8e37005f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:30 +0200 Subject: PTY: add tty_port This has *no* function in the PTY driver yet. However as the tty buffers will move to the tty_port structure, we will need tty_port for all TTYs in the system, PTY inclusive. For PTYs this is ensured by allocating 2 tty_port's in pty_install, i.e. where the tty->link is allocated. Both tty_port's are properly assigned to each end of the tty. Freeing is done at the same place where tty is freed, i.e. in tty->ops->cleanup. This means BTW that tty_port does not outlive TTY in PTY. This might be a subject to change in the future if we see some problems. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 881888f..b50fc1c 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -286,12 +286,15 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, bool legacy) { struct tty_struct *o_tty; + struct tty_port *ports[2]; int idx = tty->index; int retval = -ENOMEM; o_tty = alloc_tty_struct(); - if (!o_tty) - goto err; + ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); + ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); + if (!o_tty || !ports[0] || !ports[1]) + goto err_free_tty; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ goto err_free_tty; @@ -335,6 +338,10 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, /* Establish the links in both directions */ tty->link = o_tty; o_tty->link = tty; + tty_port_init(ports[0]); + tty_port_init(ports[1]); + o_tty->port = ports[0]; + tty->port = ports[1]; tty_driver_kref_get(driver); tty->count++; @@ -348,11 +355,17 @@ err_deinit_tty: deinitialize_tty_struct(o_tty); module_put(o_tty->driver->owner); err_free_tty: + kfree(ports[0]); + kfree(ports[1]); free_tty_struct(o_tty); -err: return retval; } +static void pty_cleanup(struct tty_struct *tty) +{ + kfree(tty->port); +} + /* Traditional BSD devices */ #ifdef CONFIG_LEGACY_PTYS @@ -391,6 +404,7 @@ static const struct tty_operations master_pty_ops_bsd = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_bsd_ioctl, + .cleanup = pty_cleanup, .resize = pty_resize }; @@ -404,6 +418,7 @@ static const struct tty_operations slave_pty_ops_bsd = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, + .cleanup = pty_cleanup, .resize = pty_resize }; @@ -555,6 +570,7 @@ static const struct tty_operations ptm_unix98_ops = { .set_termios = pty_set_termios, .ioctl = pty_unix98_ioctl, .shutdown = pty_unix98_shutdown, + .cleanup = pty_cleanup, .resize = pty_resize }; @@ -570,7 +586,8 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .shutdown = pty_unix98_shutdown + .shutdown = pty_unix98_shutdown, + .cleanup = pty_cleanup, }; /** -- cgit v0.10.2 From 4c2ef53d3bfb36659c47ba589f35bcab24f425c7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:31 +0200 Subject: TTY: vt, remove con_schedule_flip This is identical to tty_schedule_flip. So let us use that instead. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 48cc6f2..0b6217c 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -310,7 +310,7 @@ static void put_queue(struct vc_data *vc, int ch) if (tty) { tty_insert_flip_char(tty, ch, 0); - con_schedule_flip(tty); + tty_schedule_flip(tty); } } @@ -325,7 +325,7 @@ static void puts_queue(struct vc_data *vc, char *cp) tty_insert_flip_char(tty, *cp, 0); cp++; } - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void applkey(struct vc_data *vc, int key, char mode) @@ -586,7 +586,7 @@ static void fn_send_intr(struct vc_data *vc) if (!tty) return; tty_insert_flip_char(tty, 0, TTY_BREAK); - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void fn_scroll_forw(struct vc_data *vc) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 84cbf29..88a4914 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1380,7 +1380,7 @@ static void respond_string(const char *p, struct tty_struct *tty) tty_insert_flip_char(tty, *p, 0); p++; } - con_schedule_flip(tty); + tty_schedule_flip(tty); } static void cursor_report(struct vc_data *vc, struct tty_struct *tty) diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index daf4a3a..af9137db 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -145,16 +145,4 @@ void compute_shiftstate(void); extern unsigned int keymap_count; -/* console.c */ - -static inline void con_schedule_flip(struct tty_struct *t) -{ - unsigned long flags; - spin_lock_irqsave(&t->buf.lock, flags); - if (t->buf.tail != NULL) - t->buf.tail->commit = t->buf.tail->used; - spin_unlock_irqrestore(&t->buf.lock, flags); - schedule_work(&t->buf.work); -} - #endif -- cgit v0.10.2 From 695586ca20c56cf8cfa87160383307a288d32496 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:32 +0200 Subject: TTY: provide drivers with tty_port_install This will be used in tty_ops->install to set tty->port (and to call tty_standard_install). Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index bf6e238..1ac8abf 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -413,6 +413,14 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty, } EXPORT_SYMBOL(tty_port_close); +int tty_port_install(struct tty_port *port, struct tty_driver *driver, + struct tty_struct *tty) +{ + tty->port = port; + return tty_standard_install(driver, tty); +} +EXPORT_SYMBOL_GPL(tty_port_install); + int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) { diff --git a/include/linux/tty.h b/include/linux/tty.h index 9f47ab5..45ef71d 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -521,6 +521,8 @@ extern int tty_port_close_start(struct tty_port *port, extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); extern void tty_port_close(struct tty_port *port, struct tty_struct *tty, struct file *filp); +extern int tty_port_install(struct tty_port *port, struct tty_driver *driver, + struct tty_struct *tty); extern int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp); static inline int tty_port_users(struct tty_port *port) -- cgit v0.10.2 From bc1e99d93f096d5736c0bd3c2d17e13f27b6eb09 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:33 +0200 Subject: TTY: vt, add ->install We need to initialize the console only on the first open. This is usually what is done in the ->install hook. vt used to do this in ->open. Now we move it to ->install and use newly added helper for install: tty_port_install. It ensures tty->port to be set properly. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 88a4914..7cb53c2 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2792,41 +2792,52 @@ static void con_flush_chars(struct tty_struct *tty) /* * Allocate the console screen memory. */ -static int con_open(struct tty_struct *tty, struct file *filp) +static int con_install(struct tty_driver *driver, struct tty_struct *tty) { unsigned int currcons = tty->index; - int ret = 0; + struct vc_data *vc; + int ret; console_lock(); - if (tty->driver_data == NULL) { - ret = vc_allocate(currcons); - if (ret == 0) { - struct vc_data *vc = vc_cons[currcons].d; + ret = vc_allocate(currcons); + if (ret) + goto unlock; - /* Still being freed */ - if (vc->port.tty) { - console_unlock(); - return -ERESTARTSYS; - } - tty->driver_data = vc; - vc->port.tty = tty; + vc = vc_cons[currcons].d; - if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; - tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; - } - if (vc->vc_utf) - tty->termios->c_iflag |= IUTF8; - else - tty->termios->c_iflag &= ~IUTF8; - console_unlock(); - return ret; - } + /* Still being freed */ + if (vc->port.tty) { + ret = -ERESTARTSYS; + goto unlock; } + + ret = tty_port_install(&vc->port, driver, tty); + if (ret) + goto unlock; + + tty->driver_data = vc; + vc->port.tty = tty; + + if (!tty->winsize.ws_row && !tty->winsize.ws_col) { + tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; + tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; + } + if (vc->vc_utf) + tty->termios->c_iflag |= IUTF8; + else + tty->termios->c_iflag &= ~IUTF8; +unlock: console_unlock(); return ret; } +static int con_open(struct tty_struct *tty, struct file *filp) +{ + /* everything done in install */ + return 0; +} + + static void con_close(struct tty_struct *tty, struct file *filp) { /* Nothing to do - we defer to shutdown */ @@ -2947,6 +2958,7 @@ static int __init con_init(void) console_initcall(con_init); static const struct tty_operations con_ops = { + .install = con_install, .open = con_open, .close = con_close, .write = con_write, -- cgit v0.10.2 From ca4ff100d36b2c1da93a0a121177f73eea154471 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:34 +0200 Subject: TTY: usb-serial, use tty_port_install To have tty->port set in ->install. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 6a1b609..2dc92d5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -207,7 +207,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) if (retval) goto error_get_interface; - retval = tty_standard_install(driver, tty); + retval = tty_port_install(&port->port, driver, tty); if (retval) goto error_init_termios; -- cgit v0.10.2 From 9bb8a3d4109f3b267cca9f6f071e2298eed4f593 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:35 +0200 Subject: TTY: centralize fail paths in tty_register_driver Currently, some failures are handled in if's false branches, some at the end of tty_register_driver via goto-labels. Let us handle the failures at the end of the functions to have the failure handling at a single place. The only thing needed is to label the lines properly and jump there. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index b425c79..d6e045b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3144,10 +3144,8 @@ int tty_register_driver(struct tty_driver *driver) dev = MKDEV(driver->major, driver->minor_start); error = register_chrdev_region(dev, driver->num, driver->name); } - if (error < 0) { - kfree(p); - return error; - } + if (error < 0) + goto err_free_p; if (p) { driver->ttys = (struct tty_struct **)p; @@ -3160,13 +3158,8 @@ int tty_register_driver(struct tty_driver *driver) cdev_init(&driver->cdev, &tty_fops); driver->cdev.owner = driver->owner; error = cdev_add(&driver->cdev, dev, driver->num); - if (error) { - unregister_chrdev_region(dev, driver->num); - driver->ttys = NULL; - driver->termios = NULL; - kfree(p); - return error; - } + if (error) + goto err_unreg_char; mutex_lock(&tty_mutex); list_add(&driver->tty_drivers, &tty_drivers); @@ -3193,13 +3186,14 @@ err: list_del(&driver->tty_drivers); mutex_unlock(&tty_mutex); +err_unreg_char: unregister_chrdev_region(dev, driver->num); driver->ttys = NULL; driver->termios = NULL; +err_free_p: kfree(p); return error; } - EXPORT_SYMBOL(tty_register_driver); /* -- cgit v0.10.2 From 04831dc154df9b83c3e5fd54b18448da507871f7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:36 +0200 Subject: TTY: add ports array to tty_driver It will hold tty_port structures for all drivers which do not want to define tty->ops->install hook. We ignore PTY here because it wants 1 million lines and it installs tty_port in ->install anyway. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d6e045b..ac96f74 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1407,6 +1407,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) if (retval < 0) goto err_deinit_tty; + if (!tty->port) + tty->port = driver->ports[idx]; + /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need @@ -3094,6 +3097,7 @@ static void destruct_tty_driver(struct kref *kref) kfree(p); cdev_del(&driver->cdev); } + kfree(driver->ports); kfree(driver); } @@ -3132,6 +3136,18 @@ int tty_register_driver(struct tty_driver *driver) if (!p) return -ENOMEM; } + /* + * There is too many lines in PTY and we won't need the array there + * since it has an ->install hook where it assigns ports properly. + */ + if (driver->type != TTY_DRIVER_TYPE_PTY) { + driver->ports = kcalloc(driver->num, sizeof(struct tty_port *), + GFP_KERNEL); + if (!driver->ports) { + error = -ENOMEM; + goto err_free_p; + } + } if (!driver->major) { error = alloc_chrdev_region(&dev, driver->minor_start, @@ -3190,7 +3206,7 @@ err_unreg_char: unregister_chrdev_region(dev, driver->num); driver->ttys = NULL; driver->termios = NULL; -err_free_p: +err_free_p: /* destruct_tty_driver will free driver->ports */ kfree(p); return error; } diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 6e6dbb7..04419c1 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -313,6 +313,7 @@ struct tty_driver { * Pointer to the tty data structures */ struct tty_struct **ttys; + struct tty_port **ports; struct ktermios **termios; void *driver_state; -- cgit v0.10.2 From 057eb856eda1d957c0f1155eaa90739221f809a7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 4 Jun 2012 13:35:37 +0200 Subject: TTY: add tty_port_register_device helper This will automatically assign tty_port to tty_driver's port array for later recall in tty_init_dev. This is intended to be called instead of tty_register_device. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 1ac8abf..4e9d2b2 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -33,6 +33,15 @@ void tty_port_init(struct tty_port *port) } EXPORT_SYMBOL(tty_port_init); +struct device *tty_port_register_device(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device) +{ + driver->ports[index] = port; + return tty_register_device(driver, index, device); +} +EXPORT_SYMBOL_GPL(tty_port_register_device); + int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 45ef71d..40b18d7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -497,6 +497,9 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay); #define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock)) extern void tty_port_init(struct tty_port *port); +extern struct device *tty_port_register_device(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device); extern int tty_port_alloc_xmit_buf(struct tty_port *port); extern void tty_port_free_xmit_buf(struct tty_port *port); extern void tty_port_put(struct tty_port *port); -- cgit v0.10.2 From 2fc46915ecfbc51afcf995901f6ade7c3d503a25 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 21 May 2012 13:38:42 +0530 Subject: vt: fix race in vt_waitactive() pm_restore_console() is called from the suspend/resume path, and this calls vt_move_to_console(), which calls vt_waitactive(). There's a race in this path which causes the process which requests the suspend to sleep indefinitely waiting for an event which already happened: P1 P2 vt_move_to_console() set_console() schedule_console_callback() vt_waitactive() check n == fg_console +1 console_callback() switch_screen() vt_event_post() // no waiters vt_event_wait() // forever Fix the race by ensuring we're registered for the event before we check if it's already completed. Signed-off-by: Rabin Vincent Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 6461854..b841f56 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -110,16 +110,7 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new) wake_up_interruptible(&vt_event_waitqueue); } -/** - * vt_event_wait - wait for an event - * @vw: our event - * - * Waits for an event to occur which completes our vt_event_wait - * structure. On return the structure has wv->done set to 1 for success - * or 0 if some event such as a signal ended the wait. - */ - -static void vt_event_wait(struct vt_event_wait *vw) +static void __vt_event_queue(struct vt_event_wait *vw) { unsigned long flags; /* Prepare the event */ @@ -129,8 +120,18 @@ static void vt_event_wait(struct vt_event_wait *vw) spin_lock_irqsave(&vt_event_lock, flags); list_add(&vw->list, &vt_events); spin_unlock_irqrestore(&vt_event_lock, flags); +} + +static void __vt_event_wait(struct vt_event_wait *vw) +{ /* Wait for it to pass */ wait_event_interruptible(vt_event_waitqueue, vw->done); +} + +static void __vt_event_dequeue(struct vt_event_wait *vw) +{ + unsigned long flags; + /* Dequeue it */ spin_lock_irqsave(&vt_event_lock, flags); list_del(&vw->list); @@ -138,6 +139,22 @@ static void vt_event_wait(struct vt_event_wait *vw) } /** + * vt_event_wait - wait for an event + * @vw: our event + * + * Waits for an event to occur which completes our vt_event_wait + * structure. On return the structure has wv->done set to 1 for success + * or 0 if some event such as a signal ended the wait. + */ + +static void vt_event_wait(struct vt_event_wait *vw) +{ + __vt_event_queue(vw); + __vt_event_wait(vw); + __vt_event_dequeue(vw); +} + +/** * vt_event_wait_ioctl - event ioctl handler * @arg: argument to ioctl * @@ -177,10 +194,14 @@ int vt_waitactive(int n) { struct vt_event_wait vw; do { - if (n == fg_console + 1) - break; vw.event.event = VT_EVENT_SWITCH; - vt_event_wait(&vw); + __vt_event_queue(&vw); + if (n == fg_console + 1) { + __vt_event_dequeue(&vw); + break; + } + __vt_event_wait(&vw); + __vt_event_dequeue(&vw); if (vw.done == 0) return -EINTR; } while (vw.event.newev != n); -- cgit v0.10.2 From cfe275c2db6932e81ea23288a8a74f0b815c9513 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Thu, 14 Jun 2012 12:18:46 +0800 Subject: serial: pxa: add spin lock for console write v3: Remove empty line v2: Move local_irq_save() after clk_prepare_enable() v1: At UP mode, when cpu want to print message in kernel, it will invoke peempt_disable and disable irq. So it is safe for UP mode. For SMP mode, it is not safe to protect the HW reigsters. one CPU will run a program which will invoke printf. another CPU will run a program in kernel that invoke printk. So when second CPU is trying to printk, it will do 1. save ier register 2. enable uue bit of ier register 3. push buffer to uart fifo 4 .restore ier register when first CPU want to printf, and it happens between 1 and 4, it will enable thre bit of ier, and waiting for transmit intterupt. while step 4 will make the ier lost thre bit. add spin lock here to protect the ier register for console write. Signed-off-by: Chao Xie Signed-off-by: Haojian Zhuang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 5847a4b..9033fc6 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -670,9 +670,19 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) { struct uart_pxa_port *up = serial_pxa_ports[co->index]; unsigned int ier; + unsigned long flags; + int locked = 1; clk_prepare_enable(up->clk); + local_irq_save(flags); + if (up->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&up->port.lock); + else + spin_lock(&up->port.lock); + /* * First save the IER then disable the interrupts */ @@ -688,6 +698,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) wait_for_xmitr(up); serial_out(up, UART_IER, ier); + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); + clk_disable_unprepare(up->clk); } -- cgit v0.10.2 From e643f87f714c430062c634b5acd69a3a52279e51 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 17 Jun 2012 15:44:19 +0200 Subject: serial/amba-pl011: fix ages old copy-paste errors The PL011 driver has a number of symbols referring to "pl01x" (probably once shared with the pl010 driver) and some even named "pl010" (probably a pure copy-paste artifact). Lets name all local static functions with the prefix pl011_* for clarity. Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 4ad721f..3146648 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1211,14 +1211,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static unsigned int pl01x_tx_empty(struct uart_port *port) +static unsigned int pl011_tx_empty(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status = readw(uap->port.membase + UART01x_FR); return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } -static unsigned int pl01x_get_mctrl(struct uart_port *port) +static unsigned int pl011_get_mctrl(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int result = 0; @@ -1281,7 +1281,7 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) } #ifdef CONFIG_CONSOLE_POLL -static int pl010_get_poll_char(struct uart_port *port) +static int pl011_get_poll_char(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int status; @@ -1293,7 +1293,7 @@ static int pl010_get_poll_char(struct uart_port *port) return readw(uap->port.membase + UART01x_DR); } -static void pl010_put_poll_char(struct uart_port *port, +static void pl011_put_poll_char(struct uart_port *port, unsigned char ch) { struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -1616,7 +1616,7 @@ static const char *pl011_type(struct uart_port *port) /* * Release the memory region(s) being used by 'port' */ -static void pl010_release_port(struct uart_port *port) +static void pl011_release_port(struct uart_port *port) { release_mem_region(port->mapbase, SZ_4K); } @@ -1624,7 +1624,7 @@ static void pl010_release_port(struct uart_port *port) /* * Request the memory region(s) being used by 'port' */ -static int pl010_request_port(struct uart_port *port) +static int pl011_request_port(struct uart_port *port) { return request_mem_region(port->mapbase, SZ_4K, "uart-pl011") != NULL ? 0 : -EBUSY; @@ -1633,18 +1633,18 @@ static int pl010_request_port(struct uart_port *port) /* * Configure/autoconfigure the port. */ -static void pl010_config_port(struct uart_port *port, int flags) +static void pl011_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE) { port->type = PORT_AMBA; - pl010_request_port(port); + pl011_request_port(port); } } /* * verify the new serial_struct (for TIOCSSERIAL). */ -static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) +static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) @@ -1657,9 +1657,9 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) } static struct uart_ops amba_pl011_pops = { - .tx_empty = pl01x_tx_empty, + .tx_empty = pl011_tx_empty, .set_mctrl = pl011_set_mctrl, - .get_mctrl = pl01x_get_mctrl, + .get_mctrl = pl011_get_mctrl, .stop_tx = pl011_stop_tx, .start_tx = pl011_start_tx, .stop_rx = pl011_stop_rx, @@ -1670,13 +1670,13 @@ static struct uart_ops amba_pl011_pops = { .flush_buffer = pl011_dma_flush_buffer, .set_termios = pl011_set_termios, .type = pl011_type, - .release_port = pl010_release_port, - .request_port = pl010_request_port, - .config_port = pl010_config_port, - .verify_port = pl010_verify_port, + .release_port = pl011_release_port, + .request_port = pl011_request_port, + .config_port = pl011_config_port, + .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL - .poll_get_char = pl010_get_poll_char, - .poll_put_char = pl010_put_poll_char, + .poll_get_char = pl011_get_poll_char, + .poll_put_char = pl011_put_poll_char, #endif }; -- cgit v0.10.2 From fe89def79c48e2149abdd1e816523e69a9067191 Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Tue, 19 Jun 2012 14:00:18 -0700 Subject: pch_uart: Add eg20t_port lock field, avoid recursive spinlocks pch_uart_interrupt() takes priv->port.lock which leads to two recursive spinlock calls if low_latency==1 or CONFIG_PREEMPT_RT_FULL=y (one otherwise): pch_uart_interrupt spin_lock_irqsave(priv->port.lock, flags) case PCH_UART_IID_RDR_TO (data ready) handle_rx_to push_rx tty_port_tty_get spin_lock_irqsave(&port->lock, flags) <--- already hold this lock ... tty_flip_buffer_push ... flush_to_ldisc spin_lock_irqsave(&tty->buf.lock) spin_lock_irqsave(&tty->buf.lock) disc->ops->receive_buf(tty, char_buf) n_tty_receive_buf tty->ops->flush_chars() uart_flush_chars uart_start spin_lock_irqsave(&port->lock) <--- already hold this lock Avoid this by using a dedicated lock to protect the eg20t_port structure and IO access to its membase. This is more consistent with the 8250 driver. Ensure priv->lock is always take prior to priv->port.lock when taken at the same time. V2: Remove inadvertent whitespace change. V3: Account for oops_in_progress for the private lock in pch_console_write(). Note: Like the 8250 driver, if a printk is introduced anywhere inside the pch_console_write() critical section, the kernel will hang on a recursive spinlock on the private lock. The oops case is handled by using a trylock in the oops_in_progress case. Signed-off-by: Darren Hart CC: Tomoya MORINAGA CC: Feng Tang CC: Alexander Stein Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 4fdec6a..d291518 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -253,6 +253,9 @@ struct eg20t_port { dma_addr_t rx_buf_dma; struct dentry *debugfs; + + /* protect the eg20t_port private structure and io access to membase */ + spinlock_t lock; }; /** @@ -1058,7 +1061,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) int next = 1; u8 msr; - spin_lock_irqsave(&priv->port.lock, flags); + spin_lock_irqsave(&priv->lock, flags); handled = 0; while (next) { iid = pch_uart_hal_get_iid(priv); @@ -1116,7 +1119,7 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) handled |= (unsigned int)ret; } - spin_unlock_irqrestore(&priv->port.lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); return IRQ_RETVAL(handled); } @@ -1226,9 +1229,9 @@ static void pch_uart_break_ctl(struct uart_port *port, int ctl) unsigned long flags; priv = container_of(port, struct eg20t_port, port); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&priv->lock, flags); pch_uart_hal_set_break(priv, ctl); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); } /* Grab any interrupt resources and initialise any low level driver state. */ @@ -1376,7 +1379,8 @@ static void pch_uart_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&priv->lock, flags); + spin_lock(&port->lock); uart_update_timeout(port, termios->c_cflag, baud); rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb); @@ -1389,7 +1393,8 @@ static void pch_uart_set_termios(struct uart_port *port, tty_termios_encode_baud_rate(termios, baud, baud); out: - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock(&port->lock); + spin_unlock_irqrestore(&priv->lock, flags); } static const char *pch_uart_type(struct uart_port *port) @@ -1538,8 +1543,9 @@ pch_console_write(struct console *co, const char *s, unsigned int count) { struct eg20t_port *priv; unsigned long flags; + int priv_locked = 1; + int port_locked = 1; u8 ier; - int locked = 1; priv = pch_uart_ports[co->index]; @@ -1547,12 +1553,16 @@ pch_console_write(struct console *co, const char *s, unsigned int count) local_irq_save(flags); if (priv->port.sysrq) { - /* serial8250_handle_port() already took the lock */ - locked = 0; + spin_lock(&priv->lock); + /* serial8250_handle_port() already took the port lock */ + port_locked = 0; } else if (oops_in_progress) { - locked = spin_trylock(&priv->port.lock); - } else + priv_locked = spin_trylock(&priv->lock); + port_locked = spin_trylock(&priv->port.lock); + } else { + spin_lock(&priv->lock); spin_lock(&priv->port.lock); + } /* * First save the IER then disable the interrupts @@ -1570,8 +1580,10 @@ pch_console_write(struct console *co, const char *s, unsigned int count) wait_for_xmitr(priv, BOTH_EMPTY); iowrite8(ier, priv->membase + UART_IER); - if (locked) + if (port_locked) spin_unlock(&priv->port.lock); + if (priv_locked) + spin_unlock(&priv->lock); local_irq_restore(flags); } @@ -1669,6 +1681,8 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, pci_enable_msi(pdev); pci_set_master(pdev); + spin_lock_init(&priv->lock); + iobase = pci_resource_start(pdev, 0); mapbase = pci_resource_start(pdev, 1); priv->mapbase = mapbase; -- cgit v0.10.2 From 0a44ab41eb833d07e3ec807d87151c7164d4f075 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 22 Jun 2012 16:40:20 +0100 Subject: tty: note race we need to fix This was identified by Vincent Pillet with a high speed interface that uses low latency mode. In the low latency case we have a tiny race but it can be hit. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index ee1c268..4f34491 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1432,6 +1432,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, */ if (tty->receive_room < TTY_THRESHOLD_THROTTLE) tty_throttle(tty); + + /* FIXME: there is a tiny race here if the receive room check runs + before the other work executes and empties the buffer (upping + the receiving room and unthrottling. We then throttle and get + stuck. This has been observed and traced down by Vincent Pillet/ + We need to address this when we sort out out the rx path locking */ } int is_ignored(int sig) -- cgit v0.10.2 From f5e3bcc504c3c35cc6e06a9ee42efed7c274066b Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 29 Jun 2012 14:48:36 +0100 Subject: tty: localise the lock The termios and other changes mean the other protections needed on the driver tty arrays should be adequate. Turn it all back on. This contains pieces folded in from the fixes made to the original patches | From: Geert Uytterhoeven (fix m68k) | From: Paul Gortmaker (fix cris) | From: Jiri Kosina (lockdep) | From: Eric Dumazet (lockdep) Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 6cc4358..35819e3 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - tty_lock(); + tty_lock(tty); tmp.line = tty->index; tmp.port = state->port; tmp.flags = state->tport.flags; @@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, tmp.close_delay = state->tport.close_delay; tmp.closing_wait = state->tport.closing_wait; tmp.custom_divisor = state->custom_divisor; - tty_unlock(); + tty_unlock(tty); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; - tty_lock(); + tty_lock(tty); change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || new_serial.custom_divisor != state->custom_divisor; if (new_serial.irq || new_serial.port != state->port || new_serial.xmit_fifo_size != state->xmit_fifo_size) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, (new_serial.xmit_fifo_size != state->xmit_fifo_size) || ((new_serial.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { - tty_unlock(); + tty_unlock(tty); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, } if (new_serial.baud_base < 9600) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1116,7 +1116,7 @@ check_and_exit: } } else retval = startup(tty, state); - tty_unlock(); + tty_unlock(tty); return retval; } diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index cff5468..69e9ca2 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->port.close_wait, + wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 5c6c314..1e64050 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); - tty_lock(); + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1077,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, goto unlock; } /* block until there is a message: */ - wait_event_interruptible_tty(pInfo->read_wait, + wait_event_interruptible_tty(tty, pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } @@ -1107,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, } ret = -EPERM; unlock: - tty_unlock(); + tty_unlock(tty); return ret; } @@ -1156,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; - tty_lock(); + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1175,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); - tty_unlock(); + tty_unlock(tty); return 0; } diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index b50fc1c..d855883 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -47,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); tty->packet = 0; + /* Review - krefs on tty_link ?? */ if (!tty->link) return; tty->link->packet = 0; @@ -62,9 +63,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&devpts_mutex); } #endif - tty_unlock(); + tty_unlock(tty); tty_vhangup(tty->link); - tty_lock(); + tty_lock(tty); } } @@ -615,26 +616,27 @@ static int ptmx_open(struct inode *inode, struct file *filp) return retval; /* find a device that is not in use. */ - tty_lock(); + mutex_lock(&devpts_mutex); index = devpts_new_index(inode); - tty_unlock(); if (index < 0) { retval = index; goto err_file; } + mutex_unlock(&devpts_mutex); + mutex_lock(&tty_mutex); - mutex_lock(&devpts_mutex); tty = tty_init_dev(ptm_driver, index); - mutex_unlock(&devpts_mutex); - tty_lock(); - mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { retval = PTR_ERR(tty); goto out; } + /* The tty returned here is locked so we can safely + drop the mutex */ + mutex_unlock(&tty_mutex); + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty_add_file(tty, filp); @@ -647,16 +649,17 @@ static int ptmx_open(struct inode *inode, struct file *filp) if (retval) goto err_release; - tty_unlock(); + tty_unlock(tty); return 0; err_release: - tty_unlock(); + tty_unlock(tty); tty_release(inode, filp); return retval; out: + mutex_unlock(&tty_mutex); devpts_kill_index(inode, index); - tty_unlock(); err_file: + mutex_unlock(&devpts_mutex); tty_free_file(filp); return retval; } diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 80b6b1b..7264d4d 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) @@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); #endif - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); @@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp) */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 593d40a..5ed0daa 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("%s(%d):block_til_ready blocking on %s count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index aa1debf..45b43f1 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index a3dddc1..4a1e4f0 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, printk("%s(%d):%s block_til_ready() count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ac96f74..ca7c25d 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty) put_device(tty->dev); kfree(tty->write_buf); tty_buffer_free_all(tty); + tty->magic = 0xDEADDEAD; kfree(tty); } @@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty) } spin_unlock(&redirect_lock); - tty_lock(); + tty_lock(tty); /* some functions below drop BTM, so we need this bit */ set_bit(TTY_HUPPING, &tty->flags); @@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty) clear_bit(TTY_HUPPING, &tty->flags); tty_ldisc_enable(tty); - tty_unlock(); + tty_unlock(tty); if (f) fput(f); @@ -1103,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { mutex_lock(&tty->atomic_write_lock); - tty_lock(); + tty_lock(tty); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { - tty_unlock(); + tty_unlock(tty); tty->ops->write(tty, msg, strlen(msg)); } else - tty_unlock(); + tty_unlock(tty); tty_write_unlock(tty); } return; @@ -1403,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) } initialize_tty_struct(tty, driver, idx); + tty_lock(tty); retval = tty_driver_install_tty(driver, tty); if (retval < 0) goto err_deinit_tty; @@ -1418,9 +1420,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) retval = tty_ldisc_setup(tty, tty->link); if (retval) goto err_release_tty; + /* Return the tty locked so that it cannot vanish under the caller */ return tty; err_deinit_tty: + tty_unlock(tty); deinitialize_tty_struct(tty); free_tty_struct(tty); err_module_put: @@ -1429,6 +1433,7 @@ err_module_put: /* call the tty release_tty routine to clean out this slot */ err_release_tty: + tty_unlock(tty); printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); @@ -1631,7 +1636,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty_paranoia_check(tty, inode, __func__)) return 0; - tty_lock(); + tty_lock(tty); check_tty_count(tty, __func__); __tty_fasync(-1, filp, 0); @@ -1640,10 +1645,11 @@ int tty_release(struct inode *inode, struct file *filp) pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; + /* Review: parallel close */ o_tty = tty->link; if (tty_release_checks(tty, o_tty, idx)) { - tty_unlock(); + tty_unlock(tty); return 0; } @@ -1655,7 +1661,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(); + tty_unlock(tty); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1678,7 +1684,7 @@ int tty_release(struct inode *inode, struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); - tty_lock(); + tty_lock_pair(tty, o_tty); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1709,7 +1715,7 @@ int tty_release(struct inode *inode, struct file *filp) printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", __func__, tty_name(tty, buf)); - tty_unlock(); + tty_unlock_pair(tty, o_tty); mutex_unlock(&tty_mutex); schedule(); } @@ -1772,7 +1778,7 @@ int tty_release(struct inode *inode, struct file *filp) /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) { - tty_unlock(); + tty_unlock_pair(tty, o_tty); return 0; } @@ -1785,14 +1791,16 @@ int tty_release(struct inode *inode, struct file *filp) tty_ldisc_release(tty, o_tty); /* * The release_tty function takes care of the details of clearing - * the slots and preserving the termios structure. + * the slots and preserving the termios structure. The tty_unlock_pair + * should be safe as we keep a kref while the tty is locked (so the + * unlock never unlocks a freed tty). */ release_tty(tty, idx); + tty_unlock_pair(tty, o_tty); /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - tty_unlock(); return 0; } @@ -1896,6 +1904,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. * tty->count should protect the rest. * ->siglock protects ->signal/->sighand + * + * Note: the tty_unlock/lock cases without a ref are only safe due to + * tty_mutex */ static int tty_open(struct inode *inode, struct file *filp) @@ -1919,8 +1930,7 @@ retry_open: retval = 0; mutex_lock(&tty_mutex); - tty_lock(); - + /* This is protected by the tty_mutex */ tty = tty_open_current_tty(device, filp); if (IS_ERR(tty)) { retval = PTR_ERR(tty); @@ -1941,17 +1951,19 @@ retry_open: } if (tty) { + tty_lock(tty); retval = tty_reopen(tty); - if (retval) + if (retval < 0) { + tty_unlock(tty); tty = ERR_PTR(retval); - } else + } + } else /* Returns with the tty_lock held for now */ tty = tty_init_dev(driver, index); mutex_unlock(&tty_mutex); if (driver) tty_driver_kref_put(driver); if (IS_ERR(tty)) { - tty_unlock(); retval = PTR_ERR(tty); goto err_file; } @@ -1980,7 +1992,7 @@ retry_open: printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, retval, tty->name); #endif - tty_unlock(); /* need to call tty_release without BTM */ + tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) return retval; @@ -1992,17 +2004,15 @@ retry_open: /* * Need to reset f_op in case a hangup happened. */ - tty_lock(); if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; - tty_unlock(); goto retry_open; } - tty_unlock(); + tty_unlock(tty); mutex_lock(&tty_mutex); - tty_lock(); + tty_lock(tty); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -2010,11 +2020,10 @@ retry_open: tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); - tty_unlock(); + tty_unlock(tty); mutex_unlock(&tty_mutex); return 0; err_unlock: - tty_unlock(); mutex_unlock(&tty_mutex); /* after locks to avoid deadlock */ if (!IS_ERR_OR_NULL(driver)) @@ -2097,10 +2106,13 @@ out: static int tty_fasync(int fd, struct file *filp, int on) { + struct tty_struct *tty = file_tty(filp); int retval; - tty_lock(); + + tty_lock(tty); retval = __tty_fasync(fd, filp, on); - tty_unlock(); + tty_unlock(tty); + return retval; } @@ -2937,6 +2949,7 @@ void initialize_tty_struct(struct tty_struct *tty, tty->pgrp = NULL; tty->overrun_time = jiffies; tty_buffer_init(tty); + mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); init_waitqueue_head(&tty->write_wait); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 9911eb6..ba8be39 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -568,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); - tty_lock(); + tty_lock(tty); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. @@ -582,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { - tty_unlock(); + tty_unlock(tty); tty_ldisc_put(new_ldisc); return 0; } - tty_unlock(); + tty_unlock(tty); /* * Problem: What do we do if this blocks ? * We could deadlock here @@ -595,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_wait_until_sent(tty, 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* @@ -605,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); wait_event(tty_ldisc_wait, test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); } @@ -623,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) o_ldisc = tty->ldisc; - tty_unlock(); + tty_unlock(tty); /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -650,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) retval = tty_ldisc_wait_idle(tty, 5 * HZ); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* handle wait idle failure locked */ @@ -665,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); - tty_unlock(); + tty_unlock(tty); return -EIO; } @@ -708,7 +708,7 @@ enable: if (o_work) schedule_work(&o_tty->buf.work); mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); return retval; } @@ -816,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty) * need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); - tty_unlock(); + tty_unlock(tty); cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* At this point we have a closed ldisc and we want to @@ -831,7 +831,7 @@ retry: if (atomic_read(&tty->ldisc->users) != 1) { char cur_n[TASK_COMM_LEN], tty_n[64]; long timeout = 3 * HZ; - tty_unlock(); + tty_unlock(tty); while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { timeout = MAX_SCHEDULE_TIMEOUT; @@ -894,6 +894,23 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) tty_ldisc_enable(tty); return 0; } + +static void tty_ldisc_kill(struct tty_struct *tty) +{ + mutex_lock(&tty->ldisc_mutex); + /* + * Now kill off the ldisc + */ + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + /* Force an oops if we mess this up */ + tty->ldisc = NULL; + + /* Ensure the next open requests the N_TTY ldisc */ + tty_set_termios_ldisc(tty, N_TTY); + mutex_unlock(&tty->ldisc_mutex); +} + /** * tty_ldisc_release - release line discipline * @tty: tty being shut down @@ -912,27 +929,19 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * race with the set_ldisc code path. */ - tty_unlock(); + tty_unlock_pair(tty, o_tty); tty_ldisc_halt(tty); tty_ldisc_flush_works(tty); - tty_lock(); - - mutex_lock(&tty->ldisc_mutex); - /* - * Now kill off the ldisc - */ - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - /* Force an oops if we mess this up */ - tty->ldisc = NULL; + if (o_tty) { + tty_ldisc_halt(o_tty); + tty_ldisc_flush_works(o_tty); + } + tty_lock_pair(tty, o_tty); - /* Ensure the next open requests the N_TTY ldisc */ - tty_set_termios_ldisc(tty, N_TTY); - mutex_unlock(&tty->ldisc_mutex); - /* This will need doing differently if we need to lock */ + tty_ldisc_kill(tty); if (o_tty) - tty_ldisc_release(o_tty, NULL); + tty_ldisc_kill(o_tty); /* And the memory resources remaining (buffers, termios) will be disposed of when the kref hits zero */ diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 9ff986c..67feac9 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,29 +4,70 @@ #include #include -/* - * The 'big tty mutex' - * - * This mutex is taken and released by tty_lock() and tty_unlock(), - * replacing the older big kernel lock. - * It can no longer be taken recursively, and does not get - * released implicitly while sleeping. - * - * Don't use in new code. - */ -static DEFINE_MUTEX(big_tty_mutex); +/* Legacy tty mutex glue */ + +enum { + TTY_MUTEX_NORMAL, + TTY_MUTEX_NESTED, +}; /* * Getting the big tty mutex. */ -void __lockfunc tty_lock(void) + +static void __lockfunc tty_lock_nested(struct tty_struct *tty, + unsigned int subclass) { - mutex_lock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "L Bad %p\n", tty); + WARN_ON(1); + return; + } + tty_kref_get(tty); + mutex_lock_nested(&tty->legacy_mutex, subclass); +} + +void __lockfunc tty_lock(struct tty_struct *tty) +{ + return tty_lock_nested(tty, TTY_MUTEX_NORMAL); } EXPORT_SYMBOL(tty_lock); -void __lockfunc tty_unlock(void) +void __lockfunc tty_unlock(struct tty_struct *tty) { - mutex_unlock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "U Bad %p\n", tty); + WARN_ON(1); + return; + } + mutex_unlock(&tty->legacy_mutex); + tty_kref_put(tty); } EXPORT_SYMBOL(tty_unlock); + +/* + * Getting the big tty mutex for a pair of ttys with lock ordering + * On a non pty/tty pair tty2 can be NULL which is just fine. + */ +void __lockfunc tty_lock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + if (tty < tty2) { + tty_lock(tty); + tty_lock_nested(tty2, TTY_MUTEX_NESTED); + } else { + if (tty2 && tty2 != tty) + tty_lock(tty2); + tty_lock_nested(tty, TTY_MUTEX_NESTED); + } +} +EXPORT_SYMBOL(tty_lock_pair); + +void __lockfunc tty_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + tty_unlock(tty); + if (tty2 && tty2 != tty) + tty_unlock(tty2); +} +EXPORT_SYMBOL(tty_unlock_pair); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 4e9d2b2..a3ba776 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -239,7 +239,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(port->close_wait, + wait_event_interruptible_tty(tty, port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -305,9 +305,9 @@ int tty_port_block_til_ready(struct tty_port *port, retval = -ERESTARTSYS; break; } - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } finish_wait(&port->open_wait, &wait); diff --git a/include/linux/tty.h b/include/linux/tty.h index 40b18d7..7f9d7df 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -268,6 +268,7 @@ struct tty_struct { struct mutex ldisc_mutex; struct tty_ldisc *ldisc; + struct mutex legacy_mutex; struct mutex termios_mutex; spinlock_t ctrl_lock; /* Termios values are protected by the termios mutex */ @@ -610,8 +611,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty, /* tty_mutex.c */ /* functions for preparation of BKL removal */ -extern void __lockfunc tty_lock(void) __acquires(tty_lock); -extern void __lockfunc tty_unlock(void) __releases(tty_lock); +extern void __lockfunc tty_lock(struct tty_struct *tty); +extern void __lockfunc tty_unlock(struct tty_struct *tty); +extern void __lockfunc tty_lock_pair(struct tty_struct *tty, + struct tty_struct *tty2); +extern void __lockfunc tty_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2); /* * this shall be called only from where BTM is held (like close) @@ -626,9 +631,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock); static inline void tty_wait_until_sent_from_close(struct tty_struct *tty, long timeout) { - tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */ + tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */ tty_wait_until_sent(tty, timeout); - tty_lock(); + tty_lock(tty); } /* @@ -643,16 +648,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty, * * Do not use in new code. */ -#define wait_event_interruptible_tty(wq, condition) \ +#define wait_event_interruptible_tty(tty, wq, condition) \ ({ \ int __ret = 0; \ if (!(condition)) { \ - __wait_event_interruptible_tty(wq, condition, __ret); \ + __wait_event_interruptible_tty(tty, wq, condition, __ret); \ } \ __ret; \ }) -#define __wait_event_interruptible_tty(wq, condition, ret) \ +#define __wait_event_interruptible_tty(tty, wq, condition, ret) \ do { \ DEFINE_WAIT(__wait); \ \ @@ -661,9 +666,9 @@ do { \ if (condition) \ break; \ if (!signal_pending(current)) { \ - tty_unlock(); \ + tty_unlock(tty); \ schedule(); \ - tty_lock(); \ + tty_lock(tty); \ continue; \ } \ ret = -ERESTARTSYS; \ diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index d1820ff..aa5d73b 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -710,9 +710,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) break; } - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); remove_wait_queue(&dev->wait, &wait); -- cgit v0.10.2 From 157a4b311c45c9aba75a990464d9680867dc8805 Mon Sep 17 00:00:00 2001 From: Christopher Brannon Date: Fri, 22 Jun 2012 08:16:34 -0500 Subject: tty: keyboard.c: Remove locking from vt_get_leds. There are three call sites for this function, and all three are called within a keyboard handler. kbd_event_lock is already held within keyboard handlers, so attempting to lock it in vt_get_leds causes deadlock. Signed-off-by: Christopher Brannon Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 0b6217c..9b4f60a 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1049,13 +1049,10 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) */ int vt_get_leds(int console, int flag) { - unsigned long flags; struct kbd_struct * kbd = kbd_table + console; int ret; - spin_lock_irqsave(&kbd_event_lock, flags); ret = vc_kbd_led(kbd, flag); - spin_unlock_irqrestore(&kbd_event_lock, flags); return ret; } -- cgit v0.10.2 From 79d753209245de3d6f02480535a8f5cf21ad02f7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Jul 2012 09:40:40 +0300 Subject: tty: double unlock on error in ptmx_open() The problem here is that we called mutex_unlock(&devpts_mutex) on the error path when we weren't holding the lock. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index d855883..a0ca083 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -618,13 +618,12 @@ static int ptmx_open(struct inode *inode, struct file *filp) /* find a device that is not in use. */ mutex_lock(&devpts_mutex); index = devpts_new_index(inode); + mutex_unlock(&devpts_mutex); if (index < 0) { retval = index; goto err_file; } - mutex_unlock(&devpts_mutex); - mutex_lock(&tty_mutex); tty = tty_init_dev(ptm_driver, index); @@ -659,7 +658,6 @@ out: mutex_unlock(&tty_mutex); devpts_kill_index(inode, index); err_file: - mutex_unlock(&devpts_mutex); tty_free_file(filp); return retval; } -- cgit v0.10.2 From 000c74d9fa14ec61411310187cfa9e43581593b5 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Jul 2012 12:59:17 +0100 Subject: usb: fix sillies in the metro USB driver Bits noticed doing the termios conversion Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 81423f7..bad5f0c 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -130,20 +130,14 @@ static void metrousb_read_int_callback(struct urb *urb) /* Set the data read from the usb port into the serial port buffer. */ tty = tty_port_tty_get(&port->port); - if (!tty) { - dev_err(&port->dev, "%s - bad tty pointer - exiting\n", - __func__); - return; - } - if (tty && urb->actual_length) { /* Loop through the data copying each byte to the tty layer. */ tty_insert_flip_string(tty, data, urb->actual_length); /* Force the data to the tty layer. */ tty_flip_buffer_push(tty); + tty_kref_put(tty); } - tty_kref_put(tty); /* Set any port variables. */ spin_lock_irqsave(&metro_priv->lock, flags); -- cgit v0.10.2 From 2655a2c76f80d91da34faa8f4e114d1793435ed3 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Jul 2012 12:59:50 +0100 Subject: 8250: use the 8250 register interface not the legacy one The old interface just copies bits over and calls the newer one. In addition we can now pass more information. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 8123f78..2b24685 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -2979,36 +2979,36 @@ void serial8250_resume_port(int line) static int __devinit serial8250_probe(struct platform_device *dev) { struct plat_serial8250_port *p = dev->dev.platform_data; - struct uart_port port; + struct uart_8250_port uart; int ret, i, irqflag = 0; - memset(&port, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); if (share_irqs) irqflag = IRQF_SHARED; for (i = 0; p && p->flags != 0; p++, i++) { - port.iobase = p->iobase; - port.membase = p->membase; - port.irq = p->irq; - port.irqflags = p->irqflags; - port.uartclk = p->uartclk; - port.regshift = p->regshift; - port.iotype = p->iotype; - port.flags = p->flags; - port.mapbase = p->mapbase; - port.hub6 = p->hub6; - port.private_data = p->private_data; - port.type = p->type; - port.serial_in = p->serial_in; - port.serial_out = p->serial_out; - port.handle_irq = p->handle_irq; - port.handle_break = p->handle_break; - port.set_termios = p->set_termios; - port.pm = p->pm; - port.dev = &dev->dev; - port.irqflags |= irqflag; - ret = serial8250_register_port(&port); + uart.port.iobase = p->iobase; + uart.port.membase = p->membase; + uart.port.irq = p->irq; + uart.port.irqflags = p->irqflags; + uart.port.uartclk = p->uartclk; + uart.port.regshift = p->regshift; + uart.port.iotype = p->iotype; + uart.port.flags = p->flags; + uart.port.mapbase = p->mapbase; + uart.port.hub6 = p->hub6; + uart.port.private_data = p->private_data; + uart.port.type = p->type; + uart.port.serial_in = p->serial_in; + uart.port.serial_out = p->serial_out; + uart.port.handle_irq = p->handle_irq; + uart.port.handle_break = p->handle_break; + uart.port.set_termios = p->set_termios; + uart.port.pm = p->pm; + uart.port.dev = &dev->dev; + uart.port.irqflags |= irqflag; + ret = serial8250_register_8250_port(&uart); if (ret < 0) { dev_err(&dev->dev, "unable to register port at index %d " "(IO%lx MEM%llx IRQ%d): %d\n", i, @@ -3081,7 +3081,7 @@ static struct platform_driver serial8250_isa_driver = { static struct platform_device *serial8250_isa_devs; /* - * serial8250_register_port and serial8250_unregister_port allows for + * serial8250_register_8250_port and serial8250_unregister_port allows for * 16x50 serial ports to be configured at run-time, to support PCMCIA * modems and PCI multiport cards. */ @@ -3198,29 +3198,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) EXPORT_SYMBOL(serial8250_register_8250_port); /** - * serial8250_register_port - register a serial port - * @port: serial port template - * - * Configure the serial port specified by the request. If the - * port exists and is in use, it is hung up and unregistered - * first. - * - * The port is then probed and if necessary the IRQ is autodetected - * If this fails an error is returned. - * - * On success the port is ready to use and the line number is returned. - */ -int serial8250_register_port(struct uart_port *port) -{ - struct uart_8250_port up; - - memset(&up, 0, sizeof(up)); - memcpy(&up.port, port, sizeof(*port)); - return serial8250_register_8250_port(&up); -} -EXPORT_SYMBOL(serial8250_register_port); - -/** * serial8250_unregister_port - remove a 16x50 serial port at runtime * @line: serial line number * diff --git a/drivers/tty/serial/8250/8250_acorn.c b/drivers/tty/serial/8250/8250_acorn.c index b0ce8c5..8574983 100644 --- a/drivers/tty/serial/8250/8250_acorn.c +++ b/drivers/tty/serial/8250/8250_acorn.c @@ -43,7 +43,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) { struct serial_card_info *info; struct serial_card_type *type = id->data; - struct uart_port port; + struct uart_8250_port uart; unsigned long bus_addr; unsigned int i; @@ -62,19 +62,19 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) ecard_set_drvdata(ec, info); - memset(&port, 0, sizeof(struct uart_port)); - port.irq = ec->irq; - port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; - port.uartclk = type->uartclk; - port.iotype = UPIO_MEM; - port.regshift = 2; - port.dev = &ec->dev; + memset(&uart, 0, sizeof(struct uart_8250_port)); + uart.port.irq = ec->irq; + uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + uart.port.uartclk = type->uartclk; + uart.port.iotype = UPIO_MEM; + uart.port.regshift = 2; + uart.port.dev = &ec->dev; for (i = 0; i < info->num_ports; i ++) { - port.membase = info->vaddr + type->offset[i]; - port.mapbase = bus_addr + type->offset[i]; + uart.port.membase = info->vaddr + type->offset[i]; + uart.port.mapbase = bus_addr + type->offset[i]; - info->ports[i] = serial8250_register_port(&port); + info->ports[i] = serial8250_register_8250_port(&uart); } return 0; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index f574eef..afb955f 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -89,7 +89,7 @@ static int dw8250_handle_irq(struct uart_port *p) static int __devinit dw8250_probe(struct platform_device *pdev) { - struct uart_port port = {}; + struct uart_8250_port uart = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct device_node *np = pdev->dev.of_node; @@ -104,28 +104,28 @@ static int __devinit dw8250_probe(struct platform_device *pdev) data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - port.private_data = data; - - spin_lock_init(&port.lock); - port.mapbase = regs->start; - port.irq = irq->start; - port.handle_irq = dw8250_handle_irq; - port.type = PORT_8250; - port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | + uart.port.private_data = data; + + spin_lock_init(&uart.port.lock); + uart.port.mapbase = regs->start; + uart.port.irq = irq->start; + uart.port.handle_irq = dw8250_handle_irq; + uart.port.type = PORT_8250; + uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; - port.dev = &pdev->dev; + uart.port.dev = &pdev->dev; - port.iotype = UPIO_MEM; - port.serial_in = dw8250_serial_in; - port.serial_out = dw8250_serial_out; + uart.port.iotype = UPIO_MEM; + uart.port.serial_in = dw8250_serial_in; + uart.port.serial_out = dw8250_serial_out; if (!of_property_read_u32(np, "reg-io-width", &val)) { switch (val) { case 1: break; case 4: - port.iotype = UPIO_MEM32; - port.serial_in = dw8250_serial_in32; - port.serial_out = dw8250_serial_out32; + uart.port.iotype = UPIO_MEM32; + uart.port.serial_in = dw8250_serial_in32; + uart.port.serial_out = dw8250_serial_out32; break; default: dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n", @@ -135,15 +135,15 @@ static int __devinit dw8250_probe(struct platform_device *pdev) } if (!of_property_read_u32(np, "reg-shift", &val)) - port.regshift = val; + uart.port.regshift = val; if (of_property_read_u32(np, "clock-frequency", &val)) { dev_err(&pdev->dev, "no clock-frequency property set\n"); return -EINVAL; } - port.uartclk = val; + uart.uart.port.uartclk = val; - data->line = serial8250_register_port(&port); + data->line = serial8250_register_8250_port(&uart); if (data->line < 0) return data->line; diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index d8c0ffb..097dff9 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -26,7 +26,7 @@ static int __init serial_init_chip(struct parisc_device *dev) { - struct uart_port port; + struct uart_8250_port uart; unsigned long address; int err; @@ -48,21 +48,21 @@ static int __init serial_init_chip(struct parisc_device *dev) if (dev->id.sversion != 0x8d) address += 0x800; - memset(&port, 0, sizeof(port)); - port.iotype = UPIO_MEM; + memset(&uart, 0, sizeof(uart)); + uart.port.iotype = UPIO_MEM; /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */ - port.uartclk = 7272727; - port.mapbase = address; - port.membase = ioremap_nocache(address, 16); - port.irq = dev->irq; - port.flags = UPF_BOOT_AUTOCONF; - port.dev = &dev->dev; - - err = serial8250_register_port(&port); + uart.port.uartclk = 7272727; + uart.port.mapbase = address; + uart.port.membase = ioremap_nocache(address, 16); + uart.port.irq = dev->irq; + uart.port.flags = UPF_BOOT_AUTOCONF; + uart.port.dev = &dev->dev; + + err = serial8250_register_8250_port(&uart); if (err < 0) { printk(KERN_WARNING - "serial8250_register_port returned error %d\n", err); - iounmap(port.membase); + "serial8250_register_8250_port returned error %d\n", err); + iounmap(uart.port.membase); return err; } diff --git a/drivers/tty/serial/8250/8250_hp300.c b/drivers/tty/serial/8250/8250_hp300.c index c13438c..8f1dd2c 100644 --- a/drivers/tty/serial/8250/8250_hp300.c +++ b/drivers/tty/serial/8250/8250_hp300.c @@ -171,7 +171,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d, return 0; } #endif - memset(&port, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); /* Memory mapped I/O */ port.iotype = UPIO_MEM; @@ -182,7 +182,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d, port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE); port.regshift = 1; port.dev = &d->dev; - line = serial8250_register_port(&port); + line = serial8250_register_8250_port(&uart); if (line < 0) { printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" @@ -210,7 +210,7 @@ static int __init hp300_8250_init(void) #ifdef CONFIG_HPAPCI int line; unsigned long base; - struct uart_port uport; + struct uart_8250_port uart; struct hp300_port *port; int i; #endif @@ -248,26 +248,26 @@ static int __init hp300_8250_init(void) if (!port) return -ENOMEM; - memset(&uport, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); base = (FRODO_BASE + FRODO_APCI_OFFSET(i)); /* Memory mapped I/O */ - uport.iotype = UPIO_MEM; - uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \ + uart.port.iotype = UPIO_MEM; + uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \ | UPF_BOOT_AUTOCONF; /* XXX - no interrupt support yet */ - uport.irq = 0; - uport.uartclk = HPAPCI_BAUD_BASE * 16; - uport.mapbase = base; - uport.membase = (char *)(base + DIO_VIRADDRBASE); - uport.regshift = 2; + uart.port.irq = 0; + uart.port.uartclk = HPAPCI_BAUD_BASE * 16; + uart.port.mapbase = base; + uart.port.membase = (char *)(base + DIO_VIRADDRBASE); + uart.port.regshift = 2; - line = serial8250_register_port(&uport); + line = serial8250_register_8250_port(&uart); if (line < 0) { printk(KERN_NOTICE "8250_hp300: register_serial() APCI" - " %d irq %d failed\n", i, uport.irq); + " %d irq %d failed\n", i, uart.port.irq); kfree(port); continue; } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 66e5909..2ef9a07 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -44,7 +44,7 @@ struct pci_serial_quirk { int (*init)(struct pci_dev *dev); int (*setup)(struct serial_private *, const struct pciserial_board *, - struct uart_port *, int); + struct uart_8250_port *, int); void (*exit)(struct pci_dev *dev); }; @@ -59,7 +59,7 @@ struct serial_private { }; static int pci_default_setup(struct serial_private*, - const struct pciserial_board*, struct uart_port*, int); + const struct pciserial_board*, struct uart_8250_port *, int); static void moan_device(const char *str, struct pci_dev *dev) { @@ -74,7 +74,7 @@ static void moan_device(const char *str, struct pci_dev *dev) } static int -setup_port(struct serial_private *priv, struct uart_port *port, +setup_port(struct serial_private *priv, struct uart_8250_port *port, int bar, int offset, int regshift) { struct pci_dev *dev = priv->dev; @@ -93,17 +93,17 @@ setup_port(struct serial_private *priv, struct uart_port *port, if (!priv->remapped_bar[bar]) return -ENOMEM; - port->iotype = UPIO_MEM; - port->iobase = 0; - port->mapbase = base + offset; - port->membase = priv->remapped_bar[bar] + offset; - port->regshift = regshift; + port->port.iotype = UPIO_MEM; + port->port.iobase = 0; + port->port.mapbase = base + offset; + port->port.membase = priv->remapped_bar[bar] + offset; + port->port.regshift = regshift; } else { - port->iotype = UPIO_PORT; - port->iobase = base + offset; - port->mapbase = 0; - port->membase = NULL; - port->regshift = 0; + port->port.iotype = UPIO_PORT; + port->port.iobase = base + offset; + port->port.mapbase = 0; + port->port.membase = NULL; + port->port.regshift = 0; } return 0; } @@ -113,7 +113,7 @@ setup_port(struct serial_private *priv, struct uart_port *port, */ static int addidata_apci7800_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar = 0, offset = board->first_offset; bar = FL_GET_BASE(board->flags); @@ -140,7 +140,7 @@ static int addidata_apci7800_setup(struct serial_private *priv, */ static int afavlab_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -195,7 +195,7 @@ static int pci_hp_diva_init(struct pci_dev *dev) static int pci_hp_diva_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int offset = board->first_offset; unsigned int bar = FL_GET_BASE(board->flags); @@ -370,7 +370,7 @@ static void __devexit pci_ni8430_exit(struct pci_dev *dev) /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */ static int sbs_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -525,7 +525,7 @@ static int pci_siig_init(struct pci_dev *dev) static int pci_siig_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0; @@ -619,7 +619,7 @@ static int pci_timedia_init(struct pci_dev *dev) static int pci_timedia_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar = 0, offset = board->first_offset; @@ -653,7 +653,7 @@ pci_timedia_setup(struct serial_private *priv, static int titan_400l_800l_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset; @@ -754,7 +754,7 @@ static int pci_ni8430_init(struct pci_dev *dev) static int pci_ni8430_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { void __iomem *p; unsigned long base, len; @@ -781,7 +781,7 @@ pci_ni8430_setup(struct serial_private *priv, static int pci_netmos_9900_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar; @@ -1035,7 +1035,7 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) static int pci_default_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { unsigned int bar, offset = board->first_offset, maxnr; @@ -1057,15 +1057,15 @@ pci_default_setup(struct serial_private *priv, static int ce4100_serial_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { int ret; ret = setup_port(priv, port, 0, 0, board->reg_shift); - port->iotype = UPIO_MEM32; - port->type = PORT_XSCALE; - port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); - port->regshift = 2; + port->port.iotype = UPIO_MEM32; + port->port.type = PORT_XSCALE; + port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); + port->port.regshift = 2; return ret; } @@ -1073,16 +1073,16 @@ ce4100_serial_setup(struct serial_private *priv, static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { return setup_port(priv, port, 2, idx * 8, 0); } static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { - port->flags |= UPF_NO_TXEN_TEST; + port->port.flags |= UPF_NO_TXEN_TEST; printk(KERN_DEBUG "serial8250: skipping TxEn test for device " "[%04x:%04x] subsystem [%04x:%04x]\n", priv->dev->vendor, @@ -1131,11 +1131,11 @@ static unsigned int kt_serial_in(struct uart_port *p, int offset) static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { - port->flags |= UPF_BUG_THRE; - port->serial_in = kt_serial_in; - port->handle_break = kt_handle_break; + port->port.flags |= UPF_BUG_THRE; + port->port.serial_in = kt_serial_in; + port->port.handle_break = kt_handle_break; return skip_tx_en_setup(priv, board, port, idx); } @@ -1151,9 +1151,9 @@ static int pci_eg20t_init(struct pci_dev *dev) static int pci_xr17c154_setup(struct serial_private *priv, const struct pciserial_board *board, - struct uart_port *port, int idx) + struct uart_8250_port *port, int idx) { - port->flags |= UPF_EXAR_EFR; + port->port.flags |= UPF_EXAR_EFR; return pci_default_setup(priv, board, port, idx); } @@ -2720,7 +2720,7 @@ serial_pci_matches(const struct pciserial_board *board, struct serial_private * pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) { - struct uart_port serial_port; + struct uart_8250_port uart; struct serial_private *priv; struct pci_serial_quirk *quirk; int rc, nr_ports, i; @@ -2760,22 +2760,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) priv->dev = dev; priv->quirk = quirk; - memset(&serial_port, 0, sizeof(struct uart_port)); - serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; - serial_port.uartclk = board->base_baud * 16; - serial_port.irq = get_pci_irq(dev, board); - serial_port.dev = &dev->dev; + memset(&uart, 0, sizeof(uart)); + uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ; + uart.port.uartclk = board->base_baud * 16; + uart.port.irq = get_pci_irq(dev, board); + uart.port.dev = &dev->dev; for (i = 0; i < nr_ports; i++) { - if (quirk->setup(priv, board, &serial_port, i)) + if (quirk->setup(priv, board, &uart, i)) break; #ifdef SERIAL_DEBUG_PCI printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n", - serial_port.iobase, serial_port.irq, serial_port.iotype); + uart.port.iobase, uart.port.irq, uart.port.iotype); #endif - priv->line[i] = serial8250_register_port(&serial_port); + priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); break; diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index a2f2365..fde5aa6 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -424,7 +424,7 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags) static int __devinit serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { - struct uart_port port; + struct uart_8250_port uart; int ret, line, flags = dev_id->driver_data; if (flags & UNKNOWN_DEV) { @@ -433,32 +433,32 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) return ret; } - memset(&port, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); if (pnp_irq_valid(dev, 0)) - port.irq = pnp_irq(dev, 0); + uart.port.irq = pnp_irq(dev, 0); if (pnp_port_valid(dev, 0)) { - port.iobase = pnp_port_start(dev, 0); - port.iotype = UPIO_PORT; + uart.port.iobase = pnp_port_start(dev, 0); + uart.port.iotype = UPIO_PORT; } else if (pnp_mem_valid(dev, 0)) { - port.mapbase = pnp_mem_start(dev, 0); - port.iotype = UPIO_MEM; - port.flags = UPF_IOREMAP; + uart.port.mapbase = pnp_mem_start(dev, 0); + uart.port.iotype = UPIO_MEM; + uart.port.flags = UPF_IOREMAP; } else return -ENODEV; #ifdef SERIAL_DEBUG_PNP printk(KERN_DEBUG "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n", - port.iobase, port.mapbase, port.irq, port.iotype); + uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype); #endif - port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) - port.flags |= UPF_SHARE_IRQ; - port.uartclk = 1843200; - port.dev = &dev->dev; + uart.port.flags |= UPF_SHARE_IRQ; + uart.port.uartclk = 1843200; + uart.port.dev = &dev->dev; - line = serial8250_register_port(&port); + line = serial8250_register_8250_port(&uart); if (line < 0) return -ENODEV; diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 29b695d..b7d48b3 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -73,7 +73,7 @@ struct serial_quirk { unsigned int prodid; int multi; /* 1 = multifunction, > 1 = # ports */ void (*config)(struct pcmcia_device *); - void (*setup)(struct pcmcia_device *, struct uart_port *); + void (*setup)(struct pcmcia_device *, struct uart_8250_port *); void (*wakeup)(struct pcmcia_device *); int (*post)(struct pcmcia_device *); }; @@ -105,9 +105,9 @@ struct serial_cfg_mem { * Elan VPU16551 UART with 14.7456MHz oscillator * manfid 0x015D, 0x4C45 */ -static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port) +static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_8250_port *uart) { - port->uartclk = 14745600; + uart->port.uartclk = 14745600; } static int quirk_post_ibm(struct pcmcia_device *link) @@ -343,25 +343,25 @@ static void serial_detach(struct pcmcia_device *link) static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, unsigned int iobase, int irq) { - struct uart_port port; + struct uart_8250_port uart; int line; - memset(&port, 0, sizeof (struct uart_port)); - port.iobase = iobase; - port.irq = irq; - port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; - port.uartclk = 1843200; - port.dev = &handle->dev; + memset(&uart, 0, sizeof(uart)); + uart.port.iobase = iobase; + uart.port.irq = irq; + uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; + uart.port.uartclk = 1843200; + uart.port.dev = &handle->dev; if (buggy_uart) - port.flags |= UPF_BUGGY_UART; + uart.port.flags |= UPF_BUGGY_UART; if (info->quirk && info->quirk->setup) - info->quirk->setup(handle, &port); + info->quirk->setup(handle, &uart); - line = serial8250_register_port(&port); + line = serial8250_register_8250_port(&uart); if (line < 0) { - printk(KERN_NOTICE "serial_cs: serial8250_register_port() at " - "0x%04lx, irq %d failed\n", (u_long)iobase, irq); + pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n", + (unsigned long)iobase, irq); return -EINVAL; } diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index a416e92..f41dcc9 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -69,7 +69,6 @@ struct uart_port; struct uart_8250_port; int serial8250_register_8250_port(struct uart_8250_port *); -int serial8250_register_port(struct uart_port *); void serial8250_unregister_port(int line); void serial8250_suspend_port(int line); void serial8250_resume_port(int line); -- cgit v0.10.2 From a2d33d87d8a4a5047597439fb917f57e4264a79a Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Jul 2012 13:00:06 +0100 Subject: 8250: propogate the bugs field Now we are using the uart_8250_port this is trivial Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 2b24685..ca42d16 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -3155,6 +3155,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.regshift = up->port.regshift; uart->port.iotype = up->port.iotype; uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF; + uart->bugs = up->bugs; uart->port.mapbase = up->port.mapbase; uart->port.private_data = up->port.private_data; if (up->port.dev) -- cgit v0.10.2 From eb26dfe8aa7eeb5a5aa0b7574550125f8aa4c3b3 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Jul 2012 13:00:31 +0100 Subject: 8250: add support for ASIX devices with a FIFO bug Information and a different patch provided by . We do it a little differently to keep the modularity and to avoid playing with RLSI. We add a new uart bug for the parity flaw and set it in the pci matches. If parity check is enabled then we drop the FIFO trigger to 1 as per the Asix reference code. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index ca42d16..44f52c6 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -2202,6 +2202,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, unsigned char cval, fcr = 0; unsigned long flags; unsigned int baud, quot; + int fifo_bug = 0; switch (termios->c_cflag & CSIZE) { case CS5: @@ -2221,8 +2222,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_cflag & CSTOPB) cval |= UART_LCR_STOP; - if (termios->c_cflag & PARENB) + if (termios->c_cflag & PARENB) { cval |= UART_LCR_PARITY; + if (up->bugs & UART_BUG_PARITY) + fifo_bug = 1; + } if (!(termios->c_cflag & PARODD)) cval |= UART_LCR_EPAR; #ifdef CMSPAR @@ -2246,7 +2250,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { fcr = uart_config[port->type].fcr; - if (baud < 2400) { + if (baud < 2400 || fifo_bug) { fcr &= ~UART_FCR_TRIGGER_MASK; fcr |= UART_FCR_TRIGGER_1; } diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index f9719d1..c335b2b 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -78,6 +78,7 @@ struct serial8250_config { #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ #define UART_BUG_NOMSR (1 << 2) /* UART has buggy MSR status bits (Au1x00) */ #define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */ +#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */ #define PROBE_RSA (1 << 0) #define PROBE_ANY (~0) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 2ef9a07..62e10fe 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1032,8 +1032,15 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) return number_uarts; } -static int -pci_default_setup(struct serial_private *priv, +static int pci_asix_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + port->bugs |= UART_BUG_PARITY; + return pci_default_setup(priv, board, port, idx); +} + +static int pci_default_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { @@ -1187,6 +1194,7 @@ pci_xr17c154_setup(struct serial_private *priv, #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d +#define PCI_VENDOR_ID_ASIX 0x9710 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1726,7 +1734,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = pci_omegapci_setup, - }, + }, + /* + * ASIX devices with FIFO bug + */ + { + .vendor = PCI_VENDOR_ID_ASIX, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_asix_setup, + }, /* * Default "match everything" terminator entry */ -- cgit v0.10.2 From 40c9f61eae9098212b6906f29f30f08f7a19b5e2 Mon Sep 17 00:00:00 2001 From: Shachar Shemesh Date: Tue, 10 Jul 2012 07:54:13 +0300 Subject: tty ldisc: Close/Reopen race prevention should check the proper flag Commit acfa747b introduced the TTY_HUPPING flag to distinguish closed TTY from currently closing ones. The test in tty_set_ldisc still remained pointing at the old flag. This causes pppd to sometimes lapse into uninterruptible sleep when killed and restarted. Signed-off-by: Shachar Shemesh Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index ba8be39..847f7ed 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -659,7 +659,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) goto enable; } - if (test_bit(TTY_HUPPED, &tty->flags)) { + if (test_bit(TTY_HUPPING, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ clear_bit(TTY_LDISC_CHANGING, &tty->flags); -- cgit v0.10.2 From 6d31a88cb2e01d46c0cb74aa5da529e1f92ae3db Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 14 Jul 2012 15:31:27 +0100 Subject: tty: revert incorrectly applied lock patch I sent GregKH this after the pre-requisites. He dropped the pre-requesites for good reason and unfortunately then applied this patch. Without this reverted you get random kernel memory corruption which will make bisecting anything between it and the properly applied patches a complete sod. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 35819e3..6cc4358 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - tty_lock(tty); + tty_lock(); tmp.line = tty->index; tmp.port = state->port; tmp.flags = state->tport.flags; @@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, tmp.close_delay = state->tport.close_delay; tmp.closing_wait = state->tport.closing_wait; tmp.custom_divisor = state->custom_divisor; - tty_unlock(tty); + tty_unlock(); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; - tty_lock(tty); + tty_lock(); change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || new_serial.custom_divisor != state->custom_divisor; if (new_serial.irq || new_serial.port != state->port || new_serial.xmit_fifo_size != state->xmit_fifo_size) { - tty_unlock(tty); + tty_unlock(); return -EINVAL; } @@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, (new_serial.xmit_fifo_size != state->xmit_fifo_size) || ((new_serial.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { - tty_unlock(tty); + tty_unlock(); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, } if (new_serial.baud_base < 9600) { - tty_unlock(tty); + tty_unlock(); return -EINVAL; } @@ -1116,7 +1116,7 @@ check_and_exit: } } else retval = startup(tty, state); - tty_unlock(tty); + tty_unlock(); return retval; } diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index 69e9ca2..cff5468 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(tty, info->port.close_wait, + wait_event_interruptible_tty(info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 1e64050..5c6c314 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); - tty_lock(tty); + tty_lock(); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1077,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, goto unlock; } /* block until there is a message: */ - wait_event_interruptible_tty(tty, pInfo->read_wait, + wait_event_interruptible_tty(pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } @@ -1107,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, } ret = -EPERM; unlock: - tty_unlock(tty); + tty_unlock(); return ret; } @@ -1156,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; - tty_lock(tty); + tty_lock(); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1175,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); - tty_unlock(tty); + tty_unlock(); return 0; } diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index a0ca083..b50fc1c 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -47,7 +47,6 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); tty->packet = 0; - /* Review - krefs on tty_link ?? */ if (!tty->link) return; tty->link->packet = 0; @@ -63,9 +62,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&devpts_mutex); } #endif - tty_unlock(tty); + tty_unlock(); tty_vhangup(tty->link); - tty_lock(tty); + tty_lock(); } } @@ -616,26 +615,26 @@ static int ptmx_open(struct inode *inode, struct file *filp) return retval; /* find a device that is not in use. */ - mutex_lock(&devpts_mutex); + tty_lock(); index = devpts_new_index(inode); - mutex_unlock(&devpts_mutex); + tty_unlock(); if (index < 0) { retval = index; goto err_file; } mutex_lock(&tty_mutex); + mutex_lock(&devpts_mutex); tty = tty_init_dev(ptm_driver, index); + mutex_unlock(&devpts_mutex); + tty_lock(); + mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { retval = PTR_ERR(tty); goto out; } - /* The tty returned here is locked so we can safely - drop the mutex */ - mutex_unlock(&tty_mutex); - set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty_add_file(tty, filp); @@ -648,15 +647,15 @@ static int ptmx_open(struct inode *inode, struct file *filp) if (retval) goto err_release; - tty_unlock(tty); + tty_unlock(); return 0; err_release: - tty_unlock(tty); + tty_unlock(); tty_release(inode, filp); return retval; out: - mutex_unlock(&tty_mutex); devpts_kill_index(inode, index); + tty_unlock(); err_file: tty_free_file(filp); return retval; diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 7264d4d..80b6b1b 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(tty, info->close_wait, + wait_event_interruptible_tty(info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) @@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); #endif - tty_unlock(tty); + tty_unlock(); schedule(); - tty_lock(tty); + tty_lock(); } set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); @@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp) */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(tty, info->close_wait, + wait_event_interruptible_tty(info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 5ed0daa..593d40a 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("%s(%d):block_til_ready blocking on %s count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(tty); + tty_unlock(); schedule(); - tty_lock(tty); + tty_lock(); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 45b43f1..aa1debf 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); - tty_unlock(tty); + tty_unlock(); schedule(); - tty_lock(tty); + tty_lock(); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 4a1e4f0..a3dddc1 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, printk("%s(%d):%s block_til_ready() count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(tty); + tty_unlock(); schedule(); - tty_lock(tty); + tty_lock(); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ca7c25d..ac96f74 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -185,7 +185,6 @@ void free_tty_struct(struct tty_struct *tty) put_device(tty->dev); kfree(tty->write_buf); tty_buffer_free_all(tty); - tty->magic = 0xDEADDEAD; kfree(tty); } @@ -574,7 +573,7 @@ void __tty_hangup(struct tty_struct *tty) } spin_unlock(&redirect_lock); - tty_lock(tty); + tty_lock(); /* some functions below drop BTM, so we need this bit */ set_bit(TTY_HUPPING, &tty->flags); @@ -667,7 +666,7 @@ void __tty_hangup(struct tty_struct *tty) clear_bit(TTY_HUPPING, &tty->flags); tty_ldisc_enable(tty); - tty_unlock(tty); + tty_unlock(); if (f) fput(f); @@ -1104,12 +1103,12 @@ void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { mutex_lock(&tty->atomic_write_lock); - tty_lock(tty); + tty_lock(); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { - tty_unlock(tty); + tty_unlock(); tty->ops->write(tty, msg, strlen(msg)); } else - tty_unlock(tty); + tty_unlock(); tty_write_unlock(tty); } return; @@ -1404,7 +1403,6 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) } initialize_tty_struct(tty, driver, idx); - tty_lock(tty); retval = tty_driver_install_tty(driver, tty); if (retval < 0) goto err_deinit_tty; @@ -1420,11 +1418,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) retval = tty_ldisc_setup(tty, tty->link); if (retval) goto err_release_tty; - /* Return the tty locked so that it cannot vanish under the caller */ return tty; err_deinit_tty: - tty_unlock(tty); deinitialize_tty_struct(tty); free_tty_struct(tty); err_module_put: @@ -1433,7 +1429,6 @@ err_module_put: /* call the tty release_tty routine to clean out this slot */ err_release_tty: - tty_unlock(tty); printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); @@ -1636,7 +1631,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty_paranoia_check(tty, inode, __func__)) return 0; - tty_lock(tty); + tty_lock(); check_tty_count(tty, __func__); __tty_fasync(-1, filp, 0); @@ -1645,11 +1640,10 @@ int tty_release(struct inode *inode, struct file *filp) pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; - /* Review: parallel close */ o_tty = tty->link; if (tty_release_checks(tty, o_tty, idx)) { - tty_unlock(tty); + tty_unlock(); return 0; } @@ -1661,7 +1655,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(tty); + tty_unlock(); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1684,7 +1678,7 @@ int tty_release(struct inode *inode, struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); - tty_lock_pair(tty, o_tty); + tty_lock(); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1715,7 +1709,7 @@ int tty_release(struct inode *inode, struct file *filp) printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", __func__, tty_name(tty, buf)); - tty_unlock_pair(tty, o_tty); + tty_unlock(); mutex_unlock(&tty_mutex); schedule(); } @@ -1778,7 +1772,7 @@ int tty_release(struct inode *inode, struct file *filp) /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) { - tty_unlock_pair(tty, o_tty); + tty_unlock(); return 0; } @@ -1791,16 +1785,14 @@ int tty_release(struct inode *inode, struct file *filp) tty_ldisc_release(tty, o_tty); /* * The release_tty function takes care of the details of clearing - * the slots and preserving the termios structure. The tty_unlock_pair - * should be safe as we keep a kref while the tty is locked (so the - * unlock never unlocks a freed tty). + * the slots and preserving the termios structure. */ release_tty(tty, idx); - tty_unlock_pair(tty, o_tty); /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); + tty_unlock(); return 0; } @@ -1904,9 +1896,6 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. * tty->count should protect the rest. * ->siglock protects ->signal/->sighand - * - * Note: the tty_unlock/lock cases without a ref are only safe due to - * tty_mutex */ static int tty_open(struct inode *inode, struct file *filp) @@ -1930,7 +1919,8 @@ retry_open: retval = 0; mutex_lock(&tty_mutex); - /* This is protected by the tty_mutex */ + tty_lock(); + tty = tty_open_current_tty(device, filp); if (IS_ERR(tty)) { retval = PTR_ERR(tty); @@ -1951,19 +1941,17 @@ retry_open: } if (tty) { - tty_lock(tty); retval = tty_reopen(tty); - if (retval < 0) { - tty_unlock(tty); + if (retval) tty = ERR_PTR(retval); - } - } else /* Returns with the tty_lock held for now */ + } else tty = tty_init_dev(driver, index); mutex_unlock(&tty_mutex); if (driver) tty_driver_kref_put(driver); if (IS_ERR(tty)) { + tty_unlock(); retval = PTR_ERR(tty); goto err_file; } @@ -1992,7 +1980,7 @@ retry_open: printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, retval, tty->name); #endif - tty_unlock(tty); /* need to call tty_release without BTM */ + tty_unlock(); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) return retval; @@ -2004,15 +1992,17 @@ retry_open: /* * Need to reset f_op in case a hangup happened. */ + tty_lock(); if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; + tty_unlock(); goto retry_open; } - tty_unlock(tty); + tty_unlock(); mutex_lock(&tty_mutex); - tty_lock(tty); + tty_lock(); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -2020,10 +2010,11 @@ retry_open: tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); - tty_unlock(tty); + tty_unlock(); mutex_unlock(&tty_mutex); return 0; err_unlock: + tty_unlock(); mutex_unlock(&tty_mutex); /* after locks to avoid deadlock */ if (!IS_ERR_OR_NULL(driver)) @@ -2106,13 +2097,10 @@ out: static int tty_fasync(int fd, struct file *filp, int on) { - struct tty_struct *tty = file_tty(filp); int retval; - - tty_lock(tty); + tty_lock(); retval = __tty_fasync(fd, filp, on); - tty_unlock(tty); - + tty_unlock(); return retval; } @@ -2949,7 +2937,6 @@ void initialize_tty_struct(struct tty_struct *tty, tty->pgrp = NULL; tty->overrun_time = jiffies; tty_buffer_init(tty); - mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); init_waitqueue_head(&tty->write_wait); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 847f7ed..6f99c99 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -568,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); - tty_lock(tty); + tty_lock(); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. @@ -582,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { - tty_unlock(tty); + tty_unlock(); tty_ldisc_put(new_ldisc); return 0; } - tty_unlock(tty); + tty_unlock(); /* * Problem: What do we do if this blocks ? * We could deadlock here @@ -595,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_wait_until_sent(tty, 0); - tty_lock(tty); + tty_lock(); mutex_lock(&tty->ldisc_mutex); /* @@ -605,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { mutex_unlock(&tty->ldisc_mutex); - tty_unlock(tty); + tty_unlock(); wait_event(tty_ldisc_wait, test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); - tty_lock(tty); + tty_lock(); mutex_lock(&tty->ldisc_mutex); } @@ -623,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) o_ldisc = tty->ldisc; - tty_unlock(tty); + tty_unlock(); /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -650,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) retval = tty_ldisc_wait_idle(tty, 5 * HZ); - tty_lock(tty); + tty_lock(); mutex_lock(&tty->ldisc_mutex); /* handle wait idle failure locked */ @@ -665,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); - tty_unlock(tty); + tty_unlock(); return -EIO; } @@ -708,7 +708,7 @@ enable: if (o_work) schedule_work(&o_tty->buf.work); mutex_unlock(&tty->ldisc_mutex); - tty_unlock(tty); + tty_unlock(); return retval; } @@ -816,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty) * need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); - tty_unlock(tty); + tty_unlock(); cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: - tty_lock(tty); + tty_lock(); mutex_lock(&tty->ldisc_mutex); /* At this point we have a closed ldisc and we want to @@ -831,7 +831,7 @@ retry: if (atomic_read(&tty->ldisc->users) != 1) { char cur_n[TASK_COMM_LEN], tty_n[64]; long timeout = 3 * HZ; - tty_unlock(tty); + tty_unlock(); while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { timeout = MAX_SCHEDULE_TIMEOUT; @@ -894,23 +894,6 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) tty_ldisc_enable(tty); return 0; } - -static void tty_ldisc_kill(struct tty_struct *tty) -{ - mutex_lock(&tty->ldisc_mutex); - /* - * Now kill off the ldisc - */ - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - /* Force an oops if we mess this up */ - tty->ldisc = NULL; - - /* Ensure the next open requests the N_TTY ldisc */ - tty_set_termios_ldisc(tty, N_TTY); - mutex_unlock(&tty->ldisc_mutex); -} - /** * tty_ldisc_release - release line discipline * @tty: tty being shut down @@ -929,19 +912,27 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * race with the set_ldisc code path. */ - tty_unlock_pair(tty, o_tty); + tty_unlock(); tty_ldisc_halt(tty); tty_ldisc_flush_works(tty); - if (o_tty) { - tty_ldisc_halt(o_tty); - tty_ldisc_flush_works(o_tty); - } - tty_lock_pair(tty, o_tty); + tty_lock(); + mutex_lock(&tty->ldisc_mutex); + /* + * Now kill off the ldisc + */ + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + /* Force an oops if we mess this up */ + tty->ldisc = NULL; + + /* Ensure the next open requests the N_TTY ldisc */ + tty_set_termios_ldisc(tty, N_TTY); + mutex_unlock(&tty->ldisc_mutex); - tty_ldisc_kill(tty); + /* This will need doing differently if we need to lock */ if (o_tty) - tty_ldisc_kill(o_tty); + tty_ldisc_release(o_tty, NULL); /* And the memory resources remaining (buffers, termios) will be disposed of when the kref hits zero */ diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 67feac9..9ff986c 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,70 +4,29 @@ #include #include -/* Legacy tty mutex glue */ - -enum { - TTY_MUTEX_NORMAL, - TTY_MUTEX_NESTED, -}; +/* + * The 'big tty mutex' + * + * This mutex is taken and released by tty_lock() and tty_unlock(), + * replacing the older big kernel lock. + * It can no longer be taken recursively, and does not get + * released implicitly while sleeping. + * + * Don't use in new code. + */ +static DEFINE_MUTEX(big_tty_mutex); /* * Getting the big tty mutex. */ - -static void __lockfunc tty_lock_nested(struct tty_struct *tty, - unsigned int subclass) +void __lockfunc tty_lock(void) { - if (tty->magic != TTY_MAGIC) { - printk(KERN_ERR "L Bad %p\n", tty); - WARN_ON(1); - return; - } - tty_kref_get(tty); - mutex_lock_nested(&tty->legacy_mutex, subclass); -} - -void __lockfunc tty_lock(struct tty_struct *tty) -{ - return tty_lock_nested(tty, TTY_MUTEX_NORMAL); + mutex_lock(&big_tty_mutex); } EXPORT_SYMBOL(tty_lock); -void __lockfunc tty_unlock(struct tty_struct *tty) +void __lockfunc tty_unlock(void) { - if (tty->magic != TTY_MAGIC) { - printk(KERN_ERR "U Bad %p\n", tty); - WARN_ON(1); - return; - } - mutex_unlock(&tty->legacy_mutex); - tty_kref_put(tty); + mutex_unlock(&big_tty_mutex); } EXPORT_SYMBOL(tty_unlock); - -/* - * Getting the big tty mutex for a pair of ttys with lock ordering - * On a non pty/tty pair tty2 can be NULL which is just fine. - */ -void __lockfunc tty_lock_pair(struct tty_struct *tty, - struct tty_struct *tty2) -{ - if (tty < tty2) { - tty_lock(tty); - tty_lock_nested(tty2, TTY_MUTEX_NESTED); - } else { - if (tty2 && tty2 != tty) - tty_lock(tty2); - tty_lock_nested(tty, TTY_MUTEX_NESTED); - } -} -EXPORT_SYMBOL(tty_lock_pair); - -void __lockfunc tty_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2) -{ - tty_unlock(tty); - if (tty2 && tty2 != tty) - tty_unlock(tty2); -} -EXPORT_SYMBOL(tty_unlock_pair); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index a3ba776..4e9d2b2 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -239,7 +239,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(tty, port->close_wait, + wait_event_interruptible_tty(port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -305,9 +305,9 @@ int tty_port_block_til_ready(struct tty_port *port, retval = -ERESTARTSYS; break; } - tty_unlock(tty); + tty_unlock(); schedule(); - tty_lock(tty); + tty_lock(); } finish_wait(&port->open_wait, &wait); diff --git a/include/linux/tty.h b/include/linux/tty.h index 7f9d7df..40b18d7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -268,7 +268,6 @@ struct tty_struct { struct mutex ldisc_mutex; struct tty_ldisc *ldisc; - struct mutex legacy_mutex; struct mutex termios_mutex; spinlock_t ctrl_lock; /* Termios values are protected by the termios mutex */ @@ -611,12 +610,8 @@ extern long vt_compat_ioctl(struct tty_struct *tty, /* tty_mutex.c */ /* functions for preparation of BKL removal */ -extern void __lockfunc tty_lock(struct tty_struct *tty); -extern void __lockfunc tty_unlock(struct tty_struct *tty); -extern void __lockfunc tty_lock_pair(struct tty_struct *tty, - struct tty_struct *tty2); -extern void __lockfunc tty_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2); +extern void __lockfunc tty_lock(void) __acquires(tty_lock); +extern void __lockfunc tty_unlock(void) __releases(tty_lock); /* * this shall be called only from where BTM is held (like close) @@ -631,9 +626,9 @@ extern void __lockfunc tty_unlock_pair(struct tty_struct *tty, static inline void tty_wait_until_sent_from_close(struct tty_struct *tty, long timeout) { - tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */ + tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */ tty_wait_until_sent(tty, timeout); - tty_lock(tty); + tty_lock(); } /* @@ -648,16 +643,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty, * * Do not use in new code. */ -#define wait_event_interruptible_tty(tty, wq, condition) \ +#define wait_event_interruptible_tty(wq, condition) \ ({ \ int __ret = 0; \ if (!(condition)) { \ - __wait_event_interruptible_tty(tty, wq, condition, __ret); \ + __wait_event_interruptible_tty(wq, condition, __ret); \ } \ __ret; \ }) -#define __wait_event_interruptible_tty(tty, wq, condition, ret) \ +#define __wait_event_interruptible_tty(wq, condition, ret) \ do { \ DEFINE_WAIT(__wait); \ \ @@ -666,9 +661,9 @@ do { \ if (condition) \ break; \ if (!signal_pending(current)) { \ - tty_unlock(tty); \ + tty_unlock(); \ schedule(); \ - tty_lock(tty); \ + tty_lock(); \ continue; \ } \ ret = -ERESTARTSYS; \ diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index aa5d73b..d1820ff 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -710,9 +710,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) break; } - tty_unlock(tty); + tty_unlock(); schedule(); - tty_lock(tty); + tty_lock(); } set_current_state(TASK_RUNNING); remove_wait_queue(&dev->wait, &wait); -- cgit v0.10.2 From adc8d746caa67fff4b53ba3e5163a6cbacc3b523 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 14 Jul 2012 15:31:47 +0100 Subject: tty: move the termios object into the tty This will let us sort out a whole pile of tty related races. The alternative would be to keep points and refcount the termios objects. However 1. They are tiny anyway 2. Many devices don't use the stored copies 3. We can remove a pty special case Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index c34785d..1ce97f4 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -338,7 +338,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; } } diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 12172a6..0bc8a6a 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -58,7 +58,7 @@ static int ath_wakeup_ar3k(struct tty_struct *tty) return status; /* Disable Automatic RTSCTS */ - memcpy(&ktermios, tty->termios, sizeof(ktermios)); + ktermios = tty->termios; ktermios.c_cflag &= ~CRTSCTS; tty_set_termios(tty, &ktermios); diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index a6d9fd2..f9aab74 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -446,8 +446,8 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old) goto out; } - iflag = tty->termios->c_iflag; - cflag = tty->termios->c_cflag; + iflag = tty->termios.c_iflag; + cflag = tty->termios.c_cflag; old_cflag = old ? old->c_cflag : cflag; gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index, iflag, cflag, old_cflag); diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 7bc5067..7a61ef6 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1009,15 +1009,15 @@ isdn_tty_change_speed(modem_info *info) quot; int i; - if (!port->tty || !port->tty->termios) + if (!port->tty) return; - cflag = port->tty->termios->c_cflag; + cflag = port->tty->termios.c_cflag; quot = i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i > 2) - port->tty->termios->c_cflag &= ~CBAUDEX; + port->tty->termios.c_cflag &= ~CBAUDEX; else i += 15; } @@ -1097,7 +1097,7 @@ isdn_tty_shutdown(modem_info *info) #endif isdn_unlock_drivers(); info->msr &= ~UART_MSR_RI; - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { + if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) { info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { isdn_tty_modem_reset_regs(info, 0); @@ -1469,13 +1469,13 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) if (!old_termios) isdn_tty_change_speed(info); else { - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_ispeed == old_termios->c_ispeed && - tty->termios->c_ospeed == old_termios->c_ospeed) + if (tty->termios.c_cflag == old_termios->c_cflag && + tty->termios.c_ispeed == old_termios->c_ispeed && + tty->termios.c_ospeed == old_termios->c_ospeed) return; isdn_tty_change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) + !(tty->termios.c_cflag & CRTSCTS)) tty->hw_stopped = 0; } } diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 5a2cbfa..372c032 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -518,7 +518,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) if (status & UART_MSR_DCTS) { port->icount.cts++; tty = tty_port_tty_get(&port->port); - if (tty && (tty->termios->c_cflag & CRTSCTS)) { + if (tty && (tty->termios.c_cflag & CRTSCTS)) { int cts = (status & UART_MSR_CTS); if (tty->hw_stopped) { if (cts) { @@ -671,12 +671,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE; port->mctrl = TIOCM_OUT2; - sdio_uart_change_speed(port, tty->termios, NULL); + sdio_uart_change_speed(port, &tty->termios, NULL); - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -850,7 +850,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -861,7 +861,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) sdio_uart_start_tx(port); } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) sdio_uart_clear_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -872,7 +872,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -887,7 +887,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) sdio_uart_set_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -898,12 +898,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct sdio_uart_port *port = tty->driver_data; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; if (sdio_uart_claim_func(port) != 0) return; - sdio_uart_change_speed(port, tty->termios, old_termios); + sdio_uart_change_speed(port, &tty->termios, old_termios); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 3352b24..30087ca 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -124,8 +124,8 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed) tty = priv->tty; mutex_lock(&tty->termios_mutex); - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; + old_termios = tty->termios; + cflag = tty->termios.c_cflag; tty_encode_baud_rate(tty, speed, speed); if (tty->ops->set_termios) tty->ops->set_termios(tty, &old_termios); @@ -281,15 +281,15 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) int cflag; mutex_lock(&tty->termios_mutex); - old_termios = *(tty->termios); - cflag = tty->termios->c_cflag; + old_termios = tty->termios; + cflag = tty->termios.c_cflag; if (stop) cflag &= ~CREAD; else cflag |= CREAD; - tty->termios->c_cflag = cflag; + tty->termios.c_cflag = cflag; if (tty->ops->set_termios) tty->ops->set_termios(tty, &old_termios); mutex_unlock(&tty->termios_mutex); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 62f30b4..7736af7 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1107,7 +1107,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) { struct hso_serial *serial = tty->driver_data; - struct ktermios *termios; if (!serial) { printk(KERN_ERR "%s: no tty structures", __func__); @@ -1119,16 +1118,15 @@ static void _hso_serial_set_termios(struct tty_struct *tty, /* * Fix up unsupported bits */ - termios = tty->termios; - termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ + tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ - termios->c_cflag &= + tty->termios.c_cflag &= ~(CSIZE /* no size */ | PARENB /* disable parity bit */ | CBAUD /* clear current baud rate */ | CBAUDEX); /* clear current buad rate */ - termios->c_cflag |= CS8; /* character size 8 bits */ + tty->termios.c_cflag |= CS8; /* character size 8 bits */ /* baud rate 115200 */ tty_encode_baud_rate(tty, 115200, 115200); @@ -1425,14 +1423,14 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) if (old) D5("Termios called with: cflags new[%d] - old[%d]", - tty->termios->c_cflag, old->c_cflag); + tty->termios.c_cflag, old->c_cflag); /* the actual setup */ spin_lock_irqsave(&serial->serial_lock, flags); if (serial->port.count) _hso_serial_set_termios(tty, old); else - tty->termios = old; + tty->termios = *old; spin_unlock_irqrestore(&serial->serial_lock, flags); /* done */ diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 6cc4358..0e8441e 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -646,7 +646,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) custom.adkcon = AC_UARTBRK; mb(); - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) info->MCR &= ~(SER_DTR|SER_RTS); rtsdtr_ctrl(info->MCR); @@ -670,7 +670,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, int bits; unsigned long flags; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* Byte size is always 8 bits plus parity bit if requested */ @@ -707,8 +707,8 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, /* If the quotient is zero refuse the change */ if (!quot && old_termios) { /* FIXME: Will need updating for new tty in the end */ - tty->termios->c_cflag &= ~CBAUD; - tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + tty->termios.c_cflag &= ~CBAUD; + tty->termios.c_cflag |= (old_termios->c_cflag & CBAUD); baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; @@ -984,7 +984,7 @@ static void rs_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) info->MCR &= ~SER_RTS; local_irq_save(flags); @@ -1012,7 +1012,7 @@ static void rs_unthrottle(struct tty_struct * tty) else rs_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) info->MCR |= SER_RTS; local_irq_save(flags); rtsdtr_ctrl(info->MCR); @@ -1330,7 +1330,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct serial_state *info = tty->driver_data; unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; change_speed(tty, info, old_termios); @@ -1347,7 +1347,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { info->MCR |= SER_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->MCR |= SER_RTS; } @@ -1358,7 +1358,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_start(tty); } @@ -1371,7 +1371,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * or not. Hence, this may change..... */ if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) + (tty->termios.c_cflag & CLOCAL)) wake_up_interruptible(&info->open_wait); #endif } diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index cff5468..e77db71 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1459,7 +1459,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) info->port.xmit_buf = NULL; free_page((unsigned long)temp); } - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR); cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR); @@ -1488,7 +1488,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) free_page((unsigned long)temp); } - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) tty_port_lower_dtr_rts(&info->port); set_bit(TTY_IO_ERROR, &tty->flags); @@ -1999,14 +1999,11 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) int baud, baud_rate = 0; int i; - if (!tty->termios) /* XXX can this happen at all? */ - return; - if (info->line == -1) return; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* * Set up the tty->alt_speed kludge @@ -2825,7 +2822,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) cy_set_line_char(info, tty); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; cy_start(tty); } @@ -2837,7 +2834,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * or not. Hence, this may change..... */ if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) + (tty->termios.c_cflag & CLOCAL)) wake_up_interruptible(&info->port.open_wait); #endif } /* cy_set_termios */ @@ -2899,7 +2896,7 @@ static void cy_throttle(struct tty_struct *tty) info->throttle = 1; } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { if (!cy_is_Z(card)) { spin_lock_irqsave(&card->card_lock, flags); cyy_change_rts_dtr(info, 0, TIOCM_RTS); @@ -2938,7 +2935,7 @@ static void cy_unthrottle(struct tty_struct *tty) cy_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { card = info->card; if (!cy_is_Z(card)) { spin_lock_irqsave(&card->card_lock, flags); diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 59c135d..3396eb9 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -400,7 +400,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); /* Clear our own DTR */ - if (!pv->tty || (pv->tty->termios->c_cflag & HUPCL)) + if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL)) hvsilib_write_mctrl(pv, 0); /* Tear down the connection */ diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index e1235ac..d593a7d 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -702,7 +702,7 @@ static void isicom_config_port(struct tty_struct *tty) /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ if (baud < 1 || baud > 4) - tty->termios->c_cflag &= ~CBAUDEX; + tty->termios.c_cflag &= ~CBAUDEX; else baud += 15; } @@ -1196,8 +1196,8 @@ static void isicom_set_termios(struct tty_struct *tty, if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) return; - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_iflag == old_termios->c_iflag) + if (tty->termios.c_cflag == old_termios->c_cflag && + tty->termios.c_iflag == old_termios->c_iflag) return; spin_lock_irqsave(&port->card->card_lock, flags); @@ -1205,7 +1205,7 @@ static void isicom_set_termios(struct tty_struct *tty, spin_unlock_irqrestore(&port->card->card_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; isicom_start(tty); } diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 324467d..89cc934 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -367,10 +367,10 @@ static int moxa_ioctl(struct tty_struct *tty, tmp.dcd = 1; ttyp = tty_port_tty_get(&p->port); - if (!ttyp || !ttyp->termios) + if (!ttyp) tmp.cflag = p->cflag; else - tmp.cflag = ttyp->termios->c_cflag; + tmp.cflag = ttyp->termios.c_cflag; tty_kref_put(ttyp); copy: if (copy_to_user(argm, &tmp, sizeof(tmp))) @@ -1178,7 +1178,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) mutex_lock(&ch->port.mutex); if (!(ch->port.flags & ASYNC_INITIALIZED)) { ch->statusflags = 0; - moxa_set_tty_param(tty, tty->termios); + moxa_set_tty_param(tty, &tty->termios); MoxaPortLineCtrl(ch, 1, 1); MoxaPortEnable(ch); MoxaSetFifo(ch, ch->type == PORT_16550A); @@ -1193,7 +1193,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) static void moxa_close(struct tty_struct *tty, struct file *filp) { struct moxa_port *ch = tty->driver_data; - ch->cflag = tty->termios->c_cflag; + ch->cflag = tty->termios.c_cflag; tty_port_close(&ch->port, tty, filp); } @@ -1464,7 +1464,7 @@ static void moxa_poll(unsigned long ignored) static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios) { - register struct ktermios *ts = tty->termios; + register struct ktermios *ts = &tty->termios; struct moxa_port *ch = tty->driver_data; int rts, cts, txflow, rxflow, xany, baud; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 90cc680..c162ee9 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -643,7 +643,7 @@ static int mxser_change_speed(struct tty_struct *tty, int ret = 0; unsigned char status; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; if (!info->ioaddr) return ret; @@ -1520,10 +1520,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) tty = tty_port_tty_get(port); - if (!tty || !tty->termios) + if (!tty) ms.cflag = ip->normal_termios.c_cflag; else - ms.cflag = tty->termios->c_cflag; + ms.cflag = tty->termios.c_cflag; tty_kref_put(tty); spin_lock_irq(&ip->slock); status = inb(ip->ioaddr + UART_MSR); @@ -1589,13 +1589,13 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) tty = tty_port_tty_get(&ip->port); - if (!tty || !tty->termios) { + if (!tty) { cflag = ip->normal_termios.c_cflag; iflag = ip->normal_termios.c_iflag; me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios); } else { - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; me->baudrate[p] = tty_get_baud_rate(tty); } tty_kref_put(tty); @@ -1853,7 +1853,7 @@ static void mxser_stoprx(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -1890,7 +1890,7 @@ static void mxser_unthrottle(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { info->MCR |= UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -1939,14 +1939,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; mxser_start(tty); } /* Handle sw stopped */ if ((old_termios->c_iflag & IXON) && - !(tty->termios->c_iflag & IXON)) { + !(tty->termios.c_iflag & IXON)) { tty->stopped = 0; if (info->board->chip_flag) { diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c43b683..7a4bf30 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1061,7 +1061,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, /* Carrier drop -> hangup */ if (tty) { if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD)) - if (!(tty->termios->c_cflag & CLOCAL)) + if (!(tty->termios.c_cflag & CLOCAL)) tty_hangup(tty); if (brk & 0x01) tty_insert_flip_char(tty, 0, TTY_BREAK); @@ -3043,13 +3043,13 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old) the RPN control message. This however rapidly gets nasty as we then have to remap modem signals each way according to whether our virtual cable is null modem etc .. */ - tty_termios_copy_hw(tty->termios, old); + tty_termios_copy_hw(&tty->termios, old); } static void gsmtty_throttle(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) dlci->modem_tx &= ~TIOCM_DTR; dlci->throttled = 1; /* Send an MSC with DTR cleared */ @@ -3059,7 +3059,7 @@ static void gsmtty_throttle(struct tty_struct *tty) static void gsmtty_unthrottle(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) dlci->modem_tx |= TIOCM_DTR; dlci->throttled = 0; /* Send an MSC with DTR set */ diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 4f34491..101790c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1466,7 +1466,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) BUG_ON(!tty); if (old) - canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; + canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON; if (canon_change) { memset(&tty->read_flags, 0, sizeof tty->read_flags); tty->canon_head = tty->read_tail; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index b50fc1c..5ad7ccc 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -231,8 +231,8 @@ out: static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - tty->termios->c_cflag &= ~(CSIZE | PARENB); - tty->termios->c_cflag |= (CS8 | CREAD); + tty->termios.c_cflag &= ~(CSIZE | PARENB); + tty->termios.c_cflag |= (CS8 | CREAD); } /** @@ -315,18 +315,10 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, driver->other->ttys[idx] = o_tty; driver->ttys[idx] = tty; } else { - tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); - if (tty->termios == NULL) - goto err_deinit_tty; - *tty->termios = driver->init_termios; - tty->termios_locked = tty->termios + 1; - - o_tty->termios = kzalloc(sizeof(struct ktermios[2]), - GFP_KERNEL); - if (o_tty->termios == NULL) - goto err_free_termios; - *o_tty->termios = driver->other->init_termios; - o_tty->termios_locked = o_tty->termios + 1; + memset(&tty->termios_locked, 0, sizeof(tty->termios_locked)); + tty->termios = driver->init_termios; + memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked)); + o_tty->termios = driver->other->init_termios; } /* @@ -349,8 +341,6 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, err_free_termios: if (legacy) tty_free_termios(tty); - else - kfree(tty->termios); err_deinit_tty: deinitialize_tty_struct(o_tty); module_put(o_tty->driver->owner); @@ -541,7 +531,6 @@ static void pty_unix98_shutdown(struct tty_struct *tty) { tty_driver_remove_tty(tty->driver, tty); /* We have our own method as we don't use the tty index */ - kfree(tty->termios); } /* We have no need to install and remove our tty objects as devpts does all diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 777d5f9..016984a 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -720,7 +720,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info, unsigned rocketMode; int bits, baud, divisor; CHANNEL_t *cp; - struct ktermios *t = tty->termios; + struct ktermios *t = &tty->termios; cp = &info->channel; cflag = t->c_cflag; @@ -978,7 +978,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) tty->alt_speed = 460800; configure_r_port(tty, info, NULL); - if (tty->termios->c_cflag & CBAUD) { + if (tty->termios.c_cflag & CBAUD) { sSetDTR(cp); sSetRTS(cp); } @@ -1089,35 +1089,35 @@ static void rp_set_termios(struct tty_struct *tty, if (rocket_paranoia_check(info, "rp_set_termios")) return; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* * This driver doesn't support CS5 or CS6 */ if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) - tty->termios->c_cflag = + tty->termios.c_cflag = ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); /* Or CMSPAR */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; configure_r_port(tty, info, old_termios); cp = &info->channel; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) { sClrDTR(cp); sClrRTS(cp); } /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { - if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) + if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) { + if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS)) sSetRTS(cp); sSetDTR(cp); } - if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { + if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rp_start(tty); } diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index bd97db2..9242d56 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -182,7 +182,7 @@ static void bfin_serial_start_tx(struct uart_port *port) * To avoid losting RX interrupt, we reset IR function * before sending data. */ - if (tty->termios->c_line == N_IRDA) + if (tty->termios.c_line == N_IRDA) bfin_serial_reset_irda(port); #ifdef CONFIG_SERIAL_BFIN_DMA diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 80b6b1b..6b705b2 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -955,7 +955,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { - tcflag_t cflags = info->port.tty->termios->c_cflag; + tcflag_t cflags = info->port.tty->termios.c_cflag; int bits; /* calc. number of bits / data byte */ @@ -1473,7 +1473,7 @@ rs_stop(struct tty_struct *tty) xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); - if (tty->termios->c_iflag & IXON ) { + if (tty->termios.c_iflag & IXON ) { xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } @@ -1496,7 +1496,7 @@ rs_start(struct tty_struct *tty) info->xmit.tail,SERIAL_XMIT_SIZE))); xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); - if (tty->termios->c_iflag & IXON ) { + if (tty->termios.c_iflag & IXON ) { xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); } @@ -2929,7 +2929,7 @@ shutdown(struct e100_serial * info) descr[i].buf = 0; } - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) { + if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) { /* hang up DTR and RTS if HUPCL is enabled */ e100_dtr(info, 0); e100_rts(info, 0); /* could check CRTSCTS before doing this */ @@ -2953,12 +2953,12 @@ change_speed(struct e100_serial *info) unsigned long flags; /* first some safety checks */ - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; if (!info->ioport) return; - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* possibly, the tx/rx should be disabled first to do this safely */ @@ -3088,7 +3088,7 @@ change_speed(struct e100_serial *info) info->ioport[REG_REC_CTRL] = info->rx_ctrl; xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty)); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); - if (info->port.tty->termios->c_iflag & IXON ) { + if (info->port.tty->termios.c_iflag & IXON ) { DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->port.tty))); xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); @@ -3355,7 +3355,7 @@ rs_throttle(struct tty_struct * tty) DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); /* Do RTS before XOFF since XOFF might take some time */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { /* Turn off RTS line */ e100_rts(info, 0); } @@ -3377,7 +3377,7 @@ rs_unthrottle(struct tty_struct * tty) DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count)); /* Do RTS before XOFF since XOFF might take some time */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { /* Assert RTS line */ e100_rts(info, 1); } @@ -3748,7 +3748,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_start(tty); } @@ -3815,7 +3815,7 @@ rs_close(struct tty_struct *tty, struct file * filp) * separate termios for callout and dialin. */ if (info->flags & ASYNC_NORMAL_ACTIVE) - info->normal_termios = *tty->termios; + info->normal_termios = tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -3998,7 +3998,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) { + if (tty->termios.c_cflag & CLOCAL) { do_clocal = 1; } @@ -4219,7 +4219,7 @@ rs_open(struct tty_struct *tty, struct file * filp) } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - *tty->termios = info->normal_termios; + tty->termios = info->normal_termios; change_speed(info); } diff --git a/drivers/tty/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c index e16894f..cc5aca7 100644 --- a/drivers/tty/serial/ioc4_serial.c +++ b/drivers/tty/serial/ioc4_serial.c @@ -1803,7 +1803,7 @@ static inline int ic4_startup_local(struct uart_port *the_port) ioc4_set_proto(port, the_port->mapbase); /* set the speed of the serial port */ - ioc4_change_speed(the_port, state->port.tty->termios, + ioc4_change_speed(the_port, &state->port.tty->termios, (struct ktermios *)0); return 0; diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 434bd88..7139796 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -161,7 +161,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) struct ktermios *termios; spin_lock_irqsave(&port->lock, lock_flags); - termios = port->state->port.tty->termios; + termios = &port->state->port.tty->termios; if (ch == termios->c_cc[VSTART]) channel->ch_bd->bd_ops->send_start_character(channel); @@ -250,7 +250,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; - termios = port->state->port.tty->termios; + termios = &port->state->port.tty->termios; channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; channel->ch_c_oflag = termios->c_oflag; @@ -283,7 +283,7 @@ static void jsm_tty_close(struct uart_port *port) jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); bd = channel->ch_bd; - ts = port->state->port.tty->termios; + ts = &port->state->port.tty->termios; channel->ch_flags &= ~(CH_STOPI); @@ -567,7 +567,7 @@ void jsm_input(struct jsm_channel *ch) *input data and return immediately. */ if (!tp || - !(tp->termios->c_cflag & CREAD) ) { + !(tp->termios.c_cflag & CREAD) ) { jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum); diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index d57f165..5c5e7e0 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1035,7 +1035,7 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, if (tty == NULL) goto exit; - termios = tty->termios; + termios = &tty->termios; if (termios == NULL) { printk(KERN_WARNING "%s: no termios?\n", __func__); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index a21dc8e..d98b1bd 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -159,7 +159,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, retval = uport->ops->startup(uport); if (retval == 0) { if (uart_console(uport) && uport->cons->cflag) { - tty->termios->c_cflag = uport->cons->cflag; + tty->termios.c_cflag = uport->cons->cflag; uport->cons->cflag = 0; } /* @@ -172,7 +172,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, * Setup the RTS and DTR signals once the * port is open and ready to respond. */ - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } @@ -240,7 +240,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Turn off DTR and RTS early. */ - if (!tty || (tty->termios->c_cflag & HUPCL)) + if (!tty || (tty->termios.c_cflag & HUPCL)) uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); uart_port_shutdown(port); @@ -440,10 +440,10 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, * If we have no tty, termios, or the port does not exist, * then we can't set the parameters for this port. */ - if (!tty || !tty->termios || uport->type == PORT_UNKNOWN) + if (!tty || uport->type == PORT_UNKNOWN) return; - termios = tty->termios; + termios = &tty->termios; /* * Set flags based on termios cflag @@ -614,7 +614,7 @@ static void uart_throttle(struct tty_struct *tty) if (I_IXOFF(tty)) uart_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) uart_clear_mctrl(state->uart_port, TIOCM_RTS); } @@ -630,7 +630,7 @@ static void uart_unthrottle(struct tty_struct *tty) uart_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) uart_set_mctrl(port, TIOCM_RTS); } @@ -1187,7 +1187,7 @@ static void uart_set_ldisc(struct tty_struct *tty) struct uart_port *uport = state->uart_port; if (uport->ops->set_ldisc) - uport->ops->set_ldisc(uport, tty->termios->c_line); + uport->ops->set_ldisc(uport, tty->termios.c_line); } static void uart_set_termios(struct tty_struct *tty, @@ -1195,7 +1195,7 @@ static void uart_set_termios(struct tty_struct *tty, { struct uart_state *state = tty->driver_data; unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; /* @@ -1206,9 +1206,9 @@ static void uart_set_termios(struct tty_struct *tty, */ #define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) if ((cflag ^ old_termios->c_cflag) == 0 && - tty->termios->c_ospeed == old_termios->c_ospeed && - tty->termios->c_ispeed == old_termios->c_ispeed && - RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) { + tty->termios.c_ospeed == old_termios->c_ospeed && + tty->termios.c_ispeed == old_termios->c_ispeed && + RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) { return; } @@ -1960,8 +1960,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) /* * If that's unset, use the tty termios setting. */ - if (port->tty && port->tty->termios && termios.c_cflag == 0) - termios = *(port->tty->termios); + if (port->tty && termios.c_cflag == 0) + termios = port->tty->termios; if (console_suspend_enabled) uart_change_pm(state, 0); diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 593d40a..bdeeb31 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1840,22 +1840,22 @@ static void shutdown(struct mgsl_struct * info) usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS + TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC ); usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE); - + /* Disable DMAEN (Port 7, Bit 14) */ /* This disconnects the DMA request signal from the ISA bus */ /* on the ISA adapter. This has no effect for the PCI adapter */ usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14)); - + /* Disable INTEN (Port 6, Bit12) */ /* This disconnects the IRQ request signal to the ISA bus */ /* on the ISA adapter. This has no effect for the PCI adapter */ usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12)); - - if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { + + if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); usc_set_serial_signals(info); } - + spin_unlock_irqrestore(&info->irq_spinlock,flags); mgsl_release_resources(info); @@ -1895,7 +1895,7 @@ static void mgsl_program_hw(struct mgsl_struct *info) usc_EnableInterrupts(info, IO_PIN); usc_get_serial_signals(info); - if (info->netcount || info->port.tty->termios->c_cflag & CREAD) + if (info->netcount || info->port.tty->termios.c_cflag & CREAD) usc_start_receiver(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); @@ -1908,14 +1908,14 @@ static void mgsl_change_params(struct mgsl_struct *info) unsigned cflag; int bits_per_char; - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -2367,8 +2367,8 @@ static void mgsl_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) mgsl_send_xchar(tty, STOP_CHAR(tty)); - - if (tty->termios->c_cflag & CRTSCTS) { + + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->irq_spinlock,flags); info->serial_signals &= ~SerialSignal_RTS; usc_set_serial_signals(info); @@ -2401,8 +2401,8 @@ static void mgsl_unthrottle(struct tty_struct * tty) else mgsl_send_xchar(tty, START_CHAR(tty)); } - - if (tty->termios->c_cflag & CRTSCTS) { + + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->irq_spinlock,flags); info->serial_signals |= SerialSignal_RTS; usc_set_serial_signals(info); @@ -3045,7 +3045,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->irq_spinlock,flags); usc_set_serial_signals(info); @@ -3054,9 +3054,9 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->serial_signals |= SerialSignal_RTS; } @@ -3067,7 +3067,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; mgsl_start(tty); } @@ -3287,7 +3287,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) + if (tty->termios.c_cflag & CLOCAL) do_clocal = true; /* Wait for carrier detect and the line to become @@ -3313,7 +3313,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, port->blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index aa1debf..f02d18a 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -785,7 +785,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -794,9 +794,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->signals |= SerialSignal_RTS; } @@ -807,7 +807,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; tx_release(tty); } @@ -1372,7 +1372,7 @@ static void throttle(struct tty_struct * tty) DBGINFO(("%s throttle\n", info->device_name)); if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->signals &= ~SerialSignal_RTS; set_signals(info); @@ -1397,7 +1397,7 @@ static void unthrottle(struct tty_struct * tty) else send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->signals |= SerialSignal_RTS; set_signals(info); @@ -2493,7 +2493,7 @@ static void shutdown(struct slgt_info *info) slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); - if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { + if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -2534,7 +2534,7 @@ static void program_hw(struct slgt_info *info) get_signals(info); if (info->netcount || - (info->port.tty && info->port.tty->termios->c_cflag & CREAD)) + (info->port.tty && info->port.tty->termios.c_cflag & CREAD)) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -2548,11 +2548,11 @@ static void change_params(struct slgt_info *info) unsigned cflag; int bits_per_char; - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; DBGINFO(("%s change_params\n", info->device_name)); - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -3292,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) + if (tty->termios.c_cflag & CLOCAL) do_clocal = true; /* Wait for carrier detect and the line to become @@ -3314,7 +3314,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, port->blocked_open++; while (1) { - if ((tty->termios->c_cflag & CBAUD)) + if ((tty->termios.c_cflag & CBAUD)) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index a3dddc1..ae75a3c 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -873,7 +873,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -882,9 +882,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->serial_signals |= SerialSignal_RTS; } @@ -895,7 +895,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; tx_release(tty); } @@ -1473,7 +1473,7 @@ static void throttle(struct tty_struct * tty) if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals &= ~SerialSignal_RTS; set_signals(info); @@ -1502,7 +1502,7 @@ static void unthrottle(struct tty_struct * tty) send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS; set_signals(info); @@ -2708,7 +2708,7 @@ static void shutdown(SLMP_INFO * info) reset_port(info); - if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { + if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -2749,7 +2749,7 @@ static void program_hw(SLMP_INFO *info) get_signals(info); - if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) ) + if (info->netcount || (info->port.tty && info->port.tty->termios.c_cflag & CREAD) ) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -2762,14 +2762,14 @@ static void change_params(SLMP_INFO *info) unsigned cflag; int bits_per_char; - if (!info->port.tty || !info->port.tty->termios) + if (!info->port.tty) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s change_params()\n", __FILE__,__LINE__, info->device_name ); - cflag = info->port.tty->termios->c_cflag; + cflag = info->port.tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -3306,7 +3306,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } - if (tty->termios->c_cflag & CLOCAL) + if (tty->termios.c_cflag & CLOCAL) do_clocal = true; /* Wait for carrier detect and the line to become @@ -3332,7 +3332,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, port->blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); set_current_state(TASK_INTERRUPTIBLE); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index ac96f74..cfd12da 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1251,19 +1251,17 @@ int tty_init_termios(struct tty_struct *tty) tp = tty->driver->termios[idx]; if (tp == NULL) { - tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); + tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); if (tp == NULL) return -ENOMEM; - memcpy(tp, &tty->driver->init_termios, - sizeof(struct ktermios)); + *tp = tty->driver->init_termios; tty->driver->termios[idx] = tp; } - tty->termios = tp; - tty->termios_locked = tp + 1; + tty->termios = *tp; /* Compatibility until drivers always set this */ - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); + tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); return 0; } EXPORT_SYMBOL_GPL(tty_init_termios); @@ -1442,10 +1440,12 @@ void tty_free_termios(struct tty_struct *tty) /* Kill this flag and push into drivers for locking etc */ if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { /* FIXME: Locking on ->termios array */ - tp = tty->termios; + tp = tty->driver->termios[idx]; tty->driver->termios[idx] = NULL; kfree(tp); } + else + *tty->driver->termios[idx] = tty->termios; } EXPORT_SYMBOL(tty_free_termios); @@ -1575,22 +1575,12 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty, __func__, idx, tty->name); return -1; } - if (tty->termios != tty->driver->termios[idx]) { - printk(KERN_DEBUG "%s: driver.termios[%d] not termios for (%s)\n", - __func__, idx, tty->name); - return -1; - } if (tty->driver->other) { if (o_tty != tty->driver->other->ttys[idx]) { printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n", __func__, idx, tty->name); return -1; } - if (o_tty->termios != tty->driver->other->termios[idx]) { - printk(KERN_DEBUG "%s: other->termios[%d] not o_termios for (%s)\n", - __func__, idx, tty->name); - return -1; - } if (o_tty->link != tty) { printk(KERN_DEBUG "%s: bad pty pointers\n", __func__); return -1; diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index a1b9a2f..d3c2bda 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -410,7 +410,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) { - tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); + tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud); } EXPORT_SYMBOL_GPL(tty_encode_baud_rate); @@ -427,7 +427,7 @@ EXPORT_SYMBOL_GPL(tty_encode_baud_rate); speed_t tty_get_baud_rate(struct tty_struct *tty) { - speed_t baud = tty_termios_baud_rate(tty->termios); + speed_t baud = tty_termios_baud_rate(&tty->termios); if (baud == 38400 && tty->alt_speed) { if (!tty->warned) { @@ -509,14 +509,14 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ mutex_lock(&tty->termios_mutex); - old_termios = *tty->termios; - *tty->termios = *new_termios; - unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); + old_termios = tty->termios; + tty->termios = *new_termios; + unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked); /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { int extproc = (old_termios.c_lflag & EXTPROC) | - (tty->termios->c_lflag & EXTPROC); + (tty->termios.c_lflag & EXTPROC); int old_flow = ((old_termios.c_iflag & IXON) && (old_termios.c_cc[VSTOP] == '\023') && (old_termios.c_cc[VSTART] == '\021')); @@ -542,7 +542,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) if (tty->ops->set_termios) (*tty->ops->set_termios)(tty, &old_termios); else - tty_termios_copy_hw(tty->termios, &old_termios); + tty_termios_copy_hw(&tty->termios, &old_termios); ld = tty_ldisc_ref(tty); if (ld != NULL) { @@ -578,7 +578,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) return retval; mutex_lock(&tty->termios_mutex); - memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); + tmp_termios = tty->termios; mutex_unlock(&tty->termios_mutex); if (opt & TERMIOS_TERMIO) { @@ -632,14 +632,14 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) static void copy_termios(struct tty_struct *tty, struct ktermios *kterm) { mutex_lock(&tty->termios_mutex); - memcpy(kterm, tty->termios, sizeof(struct ktermios)); + *kterm = tty->termios; mutex_unlock(&tty->termios_mutex); } static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm) { mutex_lock(&tty->termios_mutex); - memcpy(kterm, tty->termios_locked, sizeof(struct ktermios)); + *kterm = tty->termios_locked; mutex_unlock(&tty->termios_mutex); } @@ -707,16 +707,16 @@ static int get_sgflags(struct tty_struct *tty) { int flags = 0; - if (!(tty->termios->c_lflag & ICANON)) { - if (tty->termios->c_lflag & ISIG) + if (!(tty->termios.c_lflag & ICANON)) { + if (tty->termios.c_lflag & ISIG) flags |= 0x02; /* cbreak */ else flags |= 0x20; /* raw */ } - if (tty->termios->c_lflag & ECHO) + if (tty->termios.c_lflag & ECHO) flags |= 0x08; /* echo */ - if (tty->termios->c_oflag & OPOST) - if (tty->termios->c_oflag & ONLCR) + if (tty->termios.c_oflag & OPOST) + if (tty->termios.c_oflag & ONLCR) flags |= 0x10; /* crmod */ return flags; } @@ -726,10 +726,10 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) struct sgttyb tmp; mutex_lock(&tty->termios_mutex); - tmp.sg_ispeed = tty->termios->c_ispeed; - tmp.sg_ospeed = tty->termios->c_ospeed; - tmp.sg_erase = tty->termios->c_cc[VERASE]; - tmp.sg_kill = tty->termios->c_cc[VKILL]; + tmp.sg_ispeed = tty->termios.c_ispeed; + tmp.sg_ospeed = tty->termios.c_ospeed; + tmp.sg_erase = tty->termios.c_cc[VERASE]; + tmp.sg_kill = tty->termios.c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); mutex_unlock(&tty->termios_mutex); @@ -738,27 +738,27 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) static void set_sgflags(struct ktermios *termios, int flags) { - termios->c_iflag = ICRNL | IXON; - termios->c_oflag = 0; - termios->c_lflag = ISIG | ICANON; + termios.c_iflag = ICRNL | IXON; + termios.c_oflag = 0; + termios.c_lflag = ISIG | ICANON; if (flags & 0x02) { /* cbreak */ - termios->c_iflag = 0; - termios->c_lflag &= ~ICANON; + termios.c_iflag = 0; + termios.c_lflag &= ~ICANON; } if (flags & 0x08) { /* echo */ - termios->c_lflag |= ECHO | ECHOE | ECHOK | + termios.c_lflag |= ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; } if (flags & 0x10) { /* crmod */ - termios->c_oflag |= OPOST | ONLCR; + termios.c_oflag |= OPOST | ONLCR; } if (flags & 0x20) { /* raw */ - termios->c_iflag = 0; - termios->c_lflag &= ~(ISIG | ICANON); + termios.c_iflag = 0; + termios.c_lflag &= ~(ISIG | ICANON); } - if (!(termios->c_lflag & ICANON)) { - termios->c_cc[VMIN] = 1; - termios->c_cc[VTIME] = 0; + if (!(termios.c_lflag & ICANON)) { + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 0; } } @@ -787,7 +787,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) return -EFAULT; mutex_lock(&tty->termios_mutex); - termios = *tty->termios; + termios = tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); @@ -808,12 +808,12 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) struct tchars tmp; mutex_lock(&tty->termios_mutex); - tmp.t_intrc = tty->termios->c_cc[VINTR]; - tmp.t_quitc = tty->termios->c_cc[VQUIT]; - tmp.t_startc = tty->termios->c_cc[VSTART]; - tmp.t_stopc = tty->termios->c_cc[VSTOP]; - tmp.t_eofc = tty->termios->c_cc[VEOF]; - tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */ + tmp.t_intrc = tty->termios.c_cc[VINTR]; + tmp.t_quitc = tty->termios.c_cc[VQUIT]; + tmp.t_startc = tty->termios.c_cc[VSTART]; + tmp.t_stopc = tty->termios.c_cc[VSTOP]; + tmp.t_eofc = tty->termios.c_cc[VEOF]; + tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */ mutex_unlock(&tty->termios_mutex); return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -825,12 +825,12 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) if (copy_from_user(&tmp, tchars, sizeof(tmp))) return -EFAULT; mutex_lock(&tty->termios_mutex); - tty->termios->c_cc[VINTR] = tmp.t_intrc; - tty->termios->c_cc[VQUIT] = tmp.t_quitc; - tty->termios->c_cc[VSTART] = tmp.t_startc; - tty->termios->c_cc[VSTOP] = tmp.t_stopc; - tty->termios->c_cc[VEOF] = tmp.t_eofc; - tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ + tty->termios.c_cc[VINTR] = tmp.t_intrc; + tty->termios.c_cc[VQUIT] = tmp.t_quitc; + tty->termios.c_cc[VSTART] = tmp.t_startc; + tty->termios.c_cc[VSTOP] = tmp.t_stopc; + tty->termios.c_cc[VEOF] = tmp.t_eofc; + tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ mutex_unlock(&tty->termios_mutex); return 0; } @@ -842,14 +842,14 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) struct ltchars tmp; mutex_lock(&tty->termios_mutex); - tmp.t_suspc = tty->termios->c_cc[VSUSP]; + tmp.t_suspc = tty->termios.c_cc[VSUSP]; /* what is dsuspc anyway? */ - tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; - tmp.t_rprntc = tty->termios->c_cc[VREPRINT]; + tmp.t_dsuspc = tty->termios.c_cc[VSUSP]; + tmp.t_rprntc = tty->termios.c_cc[VREPRINT]; /* what is flushc anyway? */ - tmp.t_flushc = tty->termios->c_cc[VEOL2]; - tmp.t_werasc = tty->termios->c_cc[VWERASE]; - tmp.t_lnextc = tty->termios->c_cc[VLNEXT]; + tmp.t_flushc = tty->termios.c_cc[VEOL2]; + tmp.t_werasc = tty->termios.c_cc[VWERASE]; + tmp.t_lnextc = tty->termios.c_cc[VLNEXT]; mutex_unlock(&tty->termios_mutex); return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -862,14 +862,14 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) return -EFAULT; mutex_lock(&tty->termios_mutex); - tty->termios->c_cc[VSUSP] = tmp.t_suspc; + tty->termios.c_cc[VSUSP] = tmp.t_suspc; /* what is dsuspc anyway? */ - tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; - tty->termios->c_cc[VREPRINT] = tmp.t_rprntc; + tty->termios.c_cc[VEOL2] = tmp.t_dsuspc; + tty->termios.c_cc[VREPRINT] = tmp.t_rprntc; /* what is flushc anyway? */ - tty->termios->c_cc[VEOL2] = tmp.t_flushc; - tty->termios->c_cc[VWERASE] = tmp.t_werasc; - tty->termios->c_cc[VLNEXT] = tmp.t_lnextc; + tty->termios.c_cc[VEOL2] = tmp.t_flushc; + tty->termios.c_cc[VWERASE] = tmp.t_werasc; + tty->termios.c_cc[VLNEXT] = tmp.t_lnextc; mutex_unlock(&tty->termios_mutex); return 0; } @@ -920,12 +920,12 @@ static int tty_change_softcar(struct tty_struct *tty, int arg) struct ktermios old; mutex_lock(&tty->termios_mutex); - old = *tty->termios; - tty->termios->c_cflag &= ~CLOCAL; - tty->termios->c_cflag |= bit; + old = tty->termios; + tty->termios.c_cflag &= ~CLOCAL; + tty->termios.c_cflag |= bit; if (tty->ops->set_termios) tty->ops->set_termios(tty, &old); - if ((tty->termios->c_cflag & CLOCAL) != bit) + if ((tty->termios.c_cflag & CLOCAL) != bit) ret = -EINVAL; mutex_unlock(&tty->termios_mutex); return ret; @@ -1031,7 +1031,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, (struct termios __user *) arg)) return -EFAULT; mutex_lock(&real_tty->termios_mutex); - memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); + real_tty->termios_locked = kterm; mutex_unlock(&real_tty->termios_mutex); return 0; #else @@ -1048,7 +1048,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, (struct termios __user *) arg)) return -EFAULT; mutex_lock(&real_tty->termios_mutex); - memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios)); + real_tty->termios_locked = kterm; mutex_unlock(&real_tty->termios_mutex); return ret; #endif diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 6f99c99..e6156c6 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -413,7 +413,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); static void tty_set_termios_ldisc(struct tty_struct *tty, int num) { mutex_lock(&tty->termios_mutex); - tty->termios->c_line = num; + tty->termios.c_line = num; mutex_unlock(&tty->termios_mutex); } @@ -722,9 +722,9 @@ enable: static void tty_reset_termios(struct tty_struct *tty) { mutex_lock(&tty->termios_mutex); - *tty->termios = tty->driver->init_termios; - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + tty->termios = tty->driver->init_termios; + tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); + tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); mutex_unlock(&tty->termios_mutex); } @@ -846,7 +846,7 @@ retry: if (reset == 0) { - if (!tty_ldisc_reinit(tty, tty->termios->c_line)) + if (!tty_ldisc_reinit(tty, tty->termios.c_line)) err = tty_ldisc_open(tty, tty->ldisc); else err = 1; diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 4e9d2b2..edcb827 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -255,7 +255,7 @@ int tty_port_block_til_ready(struct tty_port *port, } if (filp->f_flags & O_NONBLOCK) { /* Indicate we are open */ - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); port->flags |= ASYNC_NORMAL_ACTIVE; return 0; @@ -279,7 +279,7 @@ int tty_port_block_til_ready(struct tty_port *port, while (1) { /* Indicate we are open */ - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); @@ -378,7 +378,7 @@ int tty_port_close_start(struct tty_port *port, /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to hang up the line */ - if (tty->termios->c_cflag & HUPCL) + if (tty->termios.c_cflag & HUPCL) tty_port_lower_dtr_rts(port); /* Don't call port->drop for the last reference. Callers will want diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7cb53c2..dbceaeb 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2823,9 +2823,9 @@ static int con_install(struct tty_driver *driver, struct tty_struct *tty) tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; } if (vc->vc_utf) - tty->termios->c_iflag |= IUTF8; + tty->termios.c_iflag |= IUTF8; else - tty->termios->c_iflag &= ~IUTF8; + tty->termios.c_iflag &= ~IUTF8; unlock: console_unlock(); return ret; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 36a2a0b..bb2e37f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -826,7 +826,7 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) { struct acm *acm = tty->driver_data; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; struct usb_cdc_line_coding newline; int newctrl = acm->ctrlout; diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index f8ce97d..3b98fb7 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -215,7 +215,7 @@ static void ark3116_release(struct usb_serial *serial) static void ark3116_init_termios(struct tty_struct *tty) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; *termios = tty_std_termios; termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -229,7 +229,7 @@ static void ark3116_set_termios(struct tty_struct *tty, { struct usb_serial *serial = port->serial; struct ark3116_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; int bps = tty_get_baud_rate(tty); int quot; diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 6b73656..a46df73 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -307,7 +307,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty, unsigned long control_state; int bad_flow_control; speed_t baud; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; iflag = termios->c_iflag; cflag = termios->c_cflag; diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 1e71079..ba5e07e1 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -469,7 +469,7 @@ static void cp210x_get_termios(struct tty_struct *tty, if (tty) { cp210x_get_termios_port(tty->driver_data, - &tty->termios->c_cflag, &baud); + &tty->termios.c_cflag, &baud); tty_encode_baud_rate(tty, baud, baud); } @@ -631,7 +631,7 @@ static void cp210x_change_speed(struct tty_struct *tty, { u32 baud; - baud = tty->termios->c_ospeed; + baud = tty->termios.c_ospeed; /* This maps the requested rate to a rate valid on cp2102 or cp2103, * or to an arbitrary rate in [1M,2M]. @@ -665,10 +665,10 @@ static void cp210x_set_termios(struct tty_struct *tty, if (!tty) return; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; old_cflag = old_termios->c_cflag; - if (tty->termios->c_ospeed != old_termios->c_ospeed) + if (tty->termios.c_ospeed != old_termios->c_ospeed) cp210x_change_speed(tty, port, old_termios); /* If the number of data bits is to be updated */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index b78c34e..be34f15 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -922,38 +922,38 @@ static void cypress_set_termios(struct tty_struct *tty, early enough */ if (!priv->termios_initialized) { if (priv->chiptype == CT_EARTHMATE) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 4800; - tty->termios->c_ospeed = 4800; + tty->termios.c_ispeed = 4800; + tty->termios.c_ospeed = 4800; } else if (priv->chiptype == CT_CYPHIDCOM) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; } else if (priv->chiptype == CT_CA42V2) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | + tty->termios = tty_std_termios; + tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; } priv->termios_initialized = 1; } spin_unlock_irqrestore(&priv->lock, flags); /* Unsupported features need clearing */ - tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS); + tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* check if there are new settings */ if (old_termios) { spin_lock_irqsave(&priv->lock, flags); - priv->tmp_termios = *(tty->termios); + priv->tmp_termios = tty->termios; spin_unlock_irqrestore(&priv->lock, flags); } @@ -1021,7 +1021,7 @@ static void cypress_set_termios(struct tty_struct *tty, "4800bps."); /* define custom termios settings for NMEA protocol */ - tty->termios->c_iflag /* input modes - */ + tty->termios.c_iflag /* input modes - */ &= ~(IGNBRK /* disable ignore break */ | BRKINT /* disable break causes interrupt */ | PARMRK /* disable mark parity errors */ @@ -1031,10 +1031,10 @@ static void cypress_set_termios(struct tty_struct *tty, | ICRNL /* disable translate CR to NL */ | IXON); /* disable enable XON/XOFF flow control */ - tty->termios->c_oflag /* output modes */ + tty->termios.c_oflag /* output modes */ &= ~OPOST; /* disable postprocess output char */ - tty->termios->c_lflag /* line discipline modes */ + tty->termios.c_lflag /* line discipline modes */ &= ~(ECHO /* disable echo input characters */ | ECHONL /* disable echo new line */ | ICANON /* disable erase, kill, werase, and rprnt @@ -1200,7 +1200,7 @@ static void cypress_read_int_callback(struct urb *urb) /* hangup, as defined in acm.c... this might be a bad place for it * though */ - if (tty && !(tty->termios->c_cflag & CLOCAL) && + if (tty && !(tty->termios.c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) { dbg("%s - calling hangup", __func__); tty_hangup(tty); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index b5cd838..afd9d2e 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -687,8 +687,8 @@ static void digi_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct digi_port *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + unsigned int iflag = tty->termios.c_iflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int old_cflag = old_termios->c_cflag; unsigned char buf[32]; @@ -709,7 +709,7 @@ static void digi_set_termios(struct tty_struct *tty, /* don't set RTS if using hardware flow control */ /* and throttling input */ modem_signals = TIOCM_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) modem_signals |= TIOCM_RTS; digi_set_modem_signals(port, modem_signals, 1); @@ -748,7 +748,7 @@ static void digi_set_termios(struct tty_struct *tty, } } /* set parity */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) { if (cflag&PARENB) { @@ -1124,8 +1124,8 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) /* set termios settings */ if (tty) { - not_termios.c_cflag = ~tty->termios->c_cflag; - not_termios.c_iflag = ~tty->termios->c_iflag; + not_termios.c_cflag = ~tty->termios.c_cflag; + not_termios.c_iflag = ~tty->termios.c_iflag; digi_set_termios(tty, port, ¬_termios); } return 0; @@ -1500,7 +1500,7 @@ static int digi_read_oob_callback(struct urb *urb) rts = 0; if (tty) - rts = tty->termios->c_cflag & CRTSCTS; + rts = tty->termios.c_cflag & CRTSCTS; if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { spin_lock(&priv->dp_port_lock); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index cdf61dd..34e8638 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -87,7 +87,7 @@ static int empeg_startup(struct usb_serial *serial) static void empeg_init_termios(struct tty_struct *tty) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; /* * The empeg-car player wants these particular tty settings. diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 499b15f..42c604bc 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -173,7 +173,7 @@ static void f81232_set_termios(struct tty_struct *tty, /* FIXME - Stubbed out for now */ /* Don't change anything if nothing has changed */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (!tty_termios_hw_change(&tty->termios, old_termios)) return; /* Do the real work here... */ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index bc912e5..4b8b41a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2081,7 +2081,7 @@ static void ftdi_set_termios(struct tty_struct *tty, { struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; __u16 urb_value; /* will hold the new flags */ diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index e1f5ccd..f435575 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1458,7 +1458,7 @@ static void edge_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { edge_port->shadowMCR &= ~MCR_RTS; status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); @@ -1497,7 +1497,7 @@ static void edge_unthrottle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { edge_port->shadowMCR |= MCR_RTS; send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); @@ -1516,9 +1516,9 @@ static void edge_set_termios(struct tty_struct *tty, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int cflag; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); + tty->termios.c_cflag, tty->termios.c_iflag); dbg("%s - old clfag %08x old iflag %08x", __func__, old_termios->c_cflag, old_termios->c_iflag); @@ -1987,7 +1987,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, tty = tty_port_tty_get(&edge_port->port->port); if (tty) { change_port_settings(tty, - edge_port, tty->termios); + edge_port, &tty->termios); tty_kref_put(tty); } @@ -2570,7 +2570,7 @@ static void change_port_settings(struct tty_struct *tty, return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; switch (cflag & CSIZE) { case CS5: diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 3936904..765978a 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1870,7 +1870,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) /* set up the port settings */ if (tty) - edge_set_termios(tty, port, tty->termios); + edge_set_termios(tty, port, &tty->termios); /* open up the port */ @@ -2272,13 +2272,13 @@ static void change_port_settings(struct tty_struct *tty, config = kmalloc (sizeof (*config), GFP_KERNEL); if (!config) { - *tty->termios = *old_termios; + tty->termios = *old_termios; dev_err(&edge_port->port->dev, "%s - out of memory\n", __func__); return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; config->wFlags = 0; @@ -2362,7 +2362,7 @@ static void change_port_settings(struct tty_struct *tty, } else dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; /* Round the baud rate */ baud = tty_get_baud_rate(tty); @@ -2408,10 +2408,10 @@ static void edge_set_termios(struct tty_struct *tty, struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int cflag; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); + tty->termios.c_cflag, tty->termios.c_iflag); dbg("%s - old clfag %08x old iflag %08x", __func__, old_termios->c_cflag, old_termios->c_iflag); dbg("%s - port %d", __func__, port->number); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index fc09414..5a96692 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -381,7 +381,7 @@ static void ir_set_termios(struct tty_struct *tty, ir_xbof = ir_xbof_change(xbof) ; /* Only speed changes are supported */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); tty_encode_baud_rate(tty, baud, baud); /* diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 22b1eb5..bf38640 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -921,7 +921,7 @@ static void iuu_set_termios(struct tty_struct *tty, { const u32 supported_mask = CMSPAR|PARENB|PARODD; struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; int status; u32 actual; u32 parity; @@ -930,7 +930,7 @@ static void iuu_set_termios(struct tty_struct *tty, u32 newval = cflag & supported_mask; /* Just use the ospeed. ispeed should be the same. */ - baud = tty->termios->c_ospeed; + baud = tty->termios.c_ospeed; dbg("%s - enter c_ospeed or baud=%d", __func__, baud); @@ -961,13 +961,13 @@ static void iuu_set_termios(struct tty_struct *tty, * settings back over and then adjust them */ if (old_termios) - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); if (status != 0) /* Set failed - return old bits */ return; /* Re-encode speed, parity and csize */ tty_encode_baud_rate(tty, baud, baud); - tty->termios->c_cflag &= ~(supported_mask|CSIZE); - tty->termios->c_cflag |= newval | csize; + tty->termios.c_cflag &= ~(supported_mask|CSIZE); + tty->termios.c_cflag |= newval | csize; } static void iuu_close(struct usb_serial_port *port) @@ -993,14 +993,14 @@ static void iuu_close(struct usb_serial_port *port) static void iuu_init_termios(struct tty_struct *tty) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 + tty->termios = tty_std_termios; + tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600 | TIOCM_CTS | CSTOPB | PARENB; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; - tty->termios->c_lflag = 0; - tty->termios->c_oflag = 0; - tty->termios->c_iflag = 0; + tty->termios.c_ispeed = 9600; + tty->termios.c_ospeed = 9600; + tty->termios.c_lflag = 0; + tty->termios.c_oflag = 0; + tty->termios.c_iflag = 0; } static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -1012,8 +1012,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) u32 actual; struct iuu_private *priv = usb_get_serial_port_data(port); - baud = tty->termios->c_ospeed; - tty->termios->c_ispeed = baud; + baud = tty->termios.c_ospeed; + tty->termios.c_ispeed = baud; /* Re-encode speed */ tty_encode_baud_rate(tty, baud, baud); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index a1b9924..6225199 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -158,7 +158,7 @@ static void keyspan_set_termios(struct tty_struct *tty, p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; device_port = port->number - port->serial->minor; /* Baud rate calculation takes baud rate as an integer @@ -179,7 +179,7 @@ static void keyspan_set_termios(struct tty_struct *tty, p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none; /* Mark/Space not supported */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; keyspan_send_setup(port, 0); } @@ -1089,7 +1089,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) device_port = port->number - port->serial->minor; if (tty) { - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* Baud rate calculation takes baud rate as an integer so other rates can be generated if desired. */ baud_rate = tty_get_baud_rate(tty); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index a4ac3cf..dcada86 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -338,7 +338,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, 7[EOMS]1: 10 bit, b0/b7 is parity 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) - HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS + HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS bit. For now, just do baud. */ @@ -353,7 +353,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty, } /* Only speed can change so copy the old h/w parameters then encode the new speed */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); tty_encode_baud_rate(tty, speed, speed); } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 5bed59c..def9ad2 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -311,12 +311,12 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) /* set up termios structure */ spin_lock_irqsave(&priv->lock, flags); - priv->termios.c_iflag = tty->termios->c_iflag; - priv->termios.c_oflag = tty->termios->c_oflag; - priv->termios.c_cflag = tty->termios->c_cflag; - priv->termios.c_lflag = tty->termios->c_lflag; + priv->termios.c_iflag = tty->termios.c_iflag; + priv->termios.c_oflag = tty->termios.c_oflag; + priv->termios.c_cflag = tty->termios.c_cflag; + priv->termios.c_lflag = tty->termios.c_lflag; for (i = 0; i < NCCS; i++) - priv->termios.c_cc[i] = tty->termios->c_cc[i]; + priv->termios.c_cc[i] = tty->termios.c_cc[i]; priv->cfg.pktlen = cfg->pktlen; priv->cfg.baudrate = cfg->baudrate; priv->cfg.databits = cfg->databits; @@ -445,9 +445,9 @@ static void klsi_105_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; + unsigned int iflag = tty->termios.c_iflag; unsigned int old_iflag = old_termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_cflag = old_termios->c_cflag; struct klsi_105_port_settings *cfg; unsigned long flags; @@ -560,7 +560,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD)) || (cflag & CSTOPB) != (old_cflag & CSTOPB)) { /* Not currently supported */ - tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB); + tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB); #if 0 priv->last_lcr = 0; @@ -587,7 +587,7 @@ static void klsi_105_set_termios(struct tty_struct *tty, || (iflag & IXON) != (old_iflag & IXON) || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { /* Not currently supported */ - tty->termios->c_cflag &= ~CRTSCTS; + tty->termios.c_cflag &= ~CRTSCTS; /* Drop DTR/RTS if no flow control otherwise assert */ #if 0 if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index fafeabb..0516a96 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -191,11 +191,11 @@ static void kobil_release(struct usb_serial *serial) static void kobil_init_termios(struct tty_struct *tty) { /* Default to echo off and other sane device settings */ - tty->termios->c_lflag = 0; - tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); - tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; + tty->termios.c_lflag = 0; + tty->termios.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); + tty->termios.c_lflag = IGNBRK | IGNPAR | IXOFF; /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ - tty->termios->c_oflag &= ~ONLCR; + tty->termios.c_oflag &= ~ONLCR; } static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -581,14 +581,14 @@ static void kobil_set_termios(struct tty_struct *tty, struct kobil_private *priv; int result; unsigned short urb_val = 0; - int c_cflag = tty->termios->c_cflag; + int c_cflag = tty->termios.c_cflag; speed_t speed; priv = usb_get_serial_port_data(port); if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { /* This device doesn't support ioctl calls */ - *tty->termios = *old; + tty->termios = *old; return; } @@ -612,7 +612,7 @@ static void kobil_set_termios(struct tty_struct *tty, urb_val |= SUSBCR_SPASB_EvenParity; } else urb_val |= SUSBCR_SPASB_NoParity; - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; tty_encode_baud_rate(tty, speed, speed); result = usb_control_msg(port->serial->dev, diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a71fa0a..df98cff 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -454,7 +454,7 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) * either. */ spin_lock_irqsave(&priv->lock, flags); - if (tty && (tty->termios->c_cflag & CBAUD)) + if (tty && (tty->termios.c_cflag & CBAUD)) priv->control_state = TIOCM_DTR | TIOCM_RTS; else priv->control_state = 0; @@ -634,7 +634,7 @@ static void mct_u232_set_termios(struct tty_struct *tty, { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned int cflag = termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned long flags; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index a07dd3c..012f67b 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1349,7 +1349,7 @@ static void mos7720_throttle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7720_port->shadowMCR &= ~UART_MCR_RTS; write_mos_reg(port->serial, port->number - port->serial->minor, MCR, mos7720_port->shadowMCR); @@ -1383,7 +1383,7 @@ static void mos7720_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7720_port->shadowMCR |= UART_MCR_RTS; write_mos_reg(port->serial, port->number - port->serial->minor, MCR, mos7720_port->shadowMCR); @@ -1604,8 +1604,8 @@ static void change_port_settings(struct tty_struct *tty, lStop = 0x00; /* 1 stop bit */ lParity = 0x00; /* No parity */ - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* Change the number of bits */ switch (cflag & CSIZE) { @@ -1753,11 +1753,11 @@ static void mos7720_set_termios(struct tty_struct *tty, dbg("%s\n", "setting termios - ASPIRE"); - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - cflag %08x iflag %08x", __func__, - tty->termios->c_cflag, - RELEVANT_IFLAG(tty->termios->c_iflag)); + tty->termios.c_cflag, + RELEVANT_IFLAG(tty->termios.c_iflag)); dbg("%s - old cflag %08x old iflag %08x", __func__, old_termios->c_cflag, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 57eca24..d2f2b5d 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -1649,7 +1649,7 @@ static void mos7840_throttle(struct tty_struct *tty) return; } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7840_port->shadowMCR &= ~MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); @@ -1692,7 +1692,7 @@ static void mos7840_unthrottle(struct tty_struct *tty) } /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { mos7840_port->shadowMCR |= MCR_RTS; status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mos7840_port->shadowMCR); @@ -1998,8 +1998,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty, lStop = LCR_STOP_1; lParity = LCR_PAR_NONE; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; /* Change the number of bits */ if (cflag & CSIZE) { @@ -2159,10 +2159,10 @@ static void mos7840_set_termios(struct tty_struct *tty, dbg("%s", "setting termios - "); - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); + tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag)); dbg("%s - old clfag %08x old iflag %08x", __func__, old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); dbg("%s - port %d", __func__, port->number); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 5976b65..9f55556 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -404,10 +404,10 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) static void oti6858_init_termios(struct tty_struct *tty) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 38400; - tty->termios->c_ospeed = 38400; + tty->termios = tty_std_termios; + tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios.c_ispeed = 38400; + tty->termios.c_ospeed = 38400; } static void oti6858_set_termios(struct tty_struct *tty, @@ -425,7 +425,7 @@ static void oti6858_set_termios(struct tty_struct *tty, return; } - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; spin_lock_irqsave(&priv->lock, flags); divisor = priv->pending_setup.divisor; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 13b8dd6..2b9108a 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -260,16 +260,16 @@ static void pl2303_set_termios(struct tty_struct *tty, serial settings even to the same values as before. Thus we actually need to filter in this specific case */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (!tty_termios_hw_change(&tty->termios, old_termios)) return; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; buf = kzalloc(7, GFP_KERNEL); if (!buf) { dev_err(&port->dev, "%s - out of memory.\n", __func__); /* Report back no change occurred */ - *tty->termios = *old_termios; + tty->termios = *old_termios; return; } diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 8dd88eb..7de6d49 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -275,7 +275,7 @@ static void qt2_set_termios(struct tty_struct *tty, { struct usb_device *dev = port->serial->dev; struct qt2_port_private *port_priv; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; u16 baud; unsigned int cflag = termios->c_cflag; u16 new_lcr = 0; @@ -408,7 +408,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) port_priv->device_port = (u8) device_port; if (tty) - qt2_set_termios(tty, port, tty->termios); + qt2_set_termios(tty, port, &tty->termios); return 0; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index d423d36..a4e4f3a 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -385,7 +385,7 @@ static int sierra_send_setup(struct usb_serial_port *port) static void sierra_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); sierra_send_setup(port); } diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index cad6089..ab68a4d 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -316,10 +316,10 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) static void spcp8x5_init_termios(struct tty_struct *tty) { /* for the 1st time call this function */ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 115200; - tty->termios->c_ospeed = 115200; + tty->termios = tty_std_termios; + tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; + tty->termios.c_ispeed = 115200; + tty->termios.c_ospeed = 115200; } /* set the serial param for transfer. we should check if we really need to @@ -330,7 +330,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, struct usb_serial *serial = port->serial; struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned short uartdata; unsigned char buf[2] = {0, 0}; @@ -340,7 +340,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, /* check that they really want us to change something */ - if (!tty_termios_hw_change(tty->termios, old_termios)) + if (!tty_termios_hw_change(&tty->termios, old_termios)) return; /* set DTR/RTS active */ diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 3fee23b..cf2d30c 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -216,7 +216,7 @@ static void ssu100_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct usb_device *dev = port->serial->dev; - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; u16 baud, divisor, remainder; unsigned int cflag = termios->c_cflag; u16 urb_value = 0; /* will hold the new flags */ @@ -322,7 +322,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) dbg("%s - set uart failed", __func__); if (tty) - ssu100_set_termios(tty, port, tty->termios); + ssu100_set_termios(tty, port, &tty->termios); return usb_serial_generic_open(tty, port); } diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index a4404f5..f502a16 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -520,7 +520,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) } if (tty) - ti_set_termios(tty, port, tty->termios); + ti_set_termios(tty, port, &tty->termios); dbg("%s - sending TI_OPEN_PORT", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -562,7 +562,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(dev, port->read_urb->pipe); if (tty) - ti_set_termios(tty, port, tty->termios); + ti_set_termios(tty, port, &tty->termios); dbg("%s - sending TI_OPEN_PORT (2)", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, @@ -831,8 +831,8 @@ static void ti_set_termios(struct tty_struct *tty, int port_number = port->number - port->serial->minor; unsigned int mcr; - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; + cflag = tty->termios.c_cflag; + iflag = tty->termios.c_iflag; dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag); dbg("%s - old clfag %08x, old iflag %08x", __func__, @@ -871,7 +871,7 @@ static void ti_set_termios(struct tty_struct *tty, } /* CMSPAR isn't supported by this driver */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; if (cflag & PARENB) { if (cflag & PARODD) { diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index da67abb..5fe2135 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -423,7 +423,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) if (port->serial->type->set_termios) port->serial->type->set_termios(tty, port, old); else - tty_termios_copy_hw(tty->termios, old); + tty_termios_copy_hw(&tty->termios, old); } static int serial_break(struct tty_struct *tty, int break_state) diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index f35971d..7c3db9e 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -67,7 +67,7 @@ void usb_wwan_set_termios(struct tty_struct *tty, struct usb_wwan_intf_private *intfdata = port->serial->private; /* Doesn't support option setting */ - tty_termios_copy_hw(tty->termios, old_termios); + tty_termios_copy_hw(&tty->termios, old_termios); if (intfdata->send_setup) intfdata->send_setup(port); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 473635e..b36077d 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -724,7 +724,7 @@ static void firm_setup_port(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct whiteheat_port_settings port_settings; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; port_settings.port = port->number + 1; diff --git a/include/linux/tty.h b/include/linux/tty.h index 40b18d7..d5e75ee 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -103,28 +103,28 @@ struct tty_bufhead { #define TTY_PARITY 3 #define TTY_OVERRUN 4 -#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR]) -#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT]) -#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE]) -#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL]) -#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF]) -#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME]) -#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN]) -#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC]) -#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART]) -#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP]) -#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP]) -#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL]) -#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT]) -#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD]) -#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE]) -#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT]) -#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2]) - -#define _I_FLAG(tty, f) ((tty)->termios->c_iflag & (f)) -#define _O_FLAG(tty, f) ((tty)->termios->c_oflag & (f)) -#define _C_FLAG(tty, f) ((tty)->termios->c_cflag & (f)) -#define _L_FLAG(tty, f) ((tty)->termios->c_lflag & (f)) +#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) +#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) +#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) +#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) +#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) +#define TIME_CHAR(tty) ((tty)->termios.c_cc[VTIME]) +#define MIN_CHAR(tty) ((tty)->termios.c_cc[VMIN]) +#define SWTC_CHAR(tty) ((tty)->termios.c_cc[VSWTC]) +#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) +#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) +#define SUSP_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) +#define EOL_CHAR(tty) ((tty)->termios.c_cc[VEOL]) +#define REPRINT_CHAR(tty) ((tty)->termios.c_cc[VREPRINT]) +#define DISCARD_CHAR(tty) ((tty)->termios.c_cc[VDISCARD]) +#define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE]) +#define LNEXT_CHAR(tty) ((tty)->termios.c_cc[VLNEXT]) +#define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2]) + +#define _I_FLAG(tty, f) ((tty)->termios.c_iflag & (f)) +#define _O_FLAG(tty, f) ((tty)->termios.c_oflag & (f)) +#define _C_FLAG(tty, f) ((tty)->termios.c_cflag & (f)) +#define _L_FLAG(tty, f) ((tty)->termios.c_lflag & (f)) #define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK) #define I_BRKINT(tty) _I_FLAG((tty), BRKINT) @@ -271,7 +271,7 @@ struct tty_struct { struct mutex termios_mutex; spinlock_t ctrl_lock; /* Termios values are protected by the termios mutex */ - struct ktermios *termios, *termios_locked; + struct ktermios termios, termios_locked; struct termiox *termiox; /* May be NULL for unsupported */ char name[64]; struct pid *pgrp; /* Protected by ctrl lock */ diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index d1820ff..363bca1 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -866,7 +866,7 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { - struct ktermios *new = tty->termios; + struct ktermios *new = &tty->termios; int old_baud_rate = tty_termios_baud_rate(old); int new_baud_rate = tty_termios_baud_rate(new); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 4e35b45..7a0d611 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -292,7 +292,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, return 0; } - if (tty->termios->c_cflag & CLOCAL) { + if (tty->termios.c_cflag & CLOCAL) { IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ ); do_clocal = 1; } @@ -319,7 +319,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, port->blocked_open++; while (1) { - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) tty_port_raise_dtr_rts(port); current->state = TASK_INTERRUPTIBLE; @@ -421,8 +421,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) * * Note this is completely usafe and doesn't work properly */ - tty->termios->c_iflag = 0; - tty->termios->c_oflag = 0; + tty->termios.c_iflag = 0; + tty->termios.c_oflag = 0; /* Insert into hash */ /* FIXME there is a window from find to here */ @@ -842,7 +842,7 @@ static void ircomm_tty_throttle(struct tty_struct *tty) ircomm_tty_send_xchar(tty, STOP_CHAR(tty)); /* Hardware flow control? */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { self->settings.dte &= ~IRCOMM_RTS; self->settings.dte |= IRCOMM_DELTA_RTS; @@ -874,7 +874,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty) } /* Using hardware flow control? */ - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); ircomm_param_request(self, IRCOMM_DTE, TRUE); diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 0eab650..b343f50 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -63,7 +63,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self, if (!self->ircomm) return; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* byte size and parity */ switch (cflag & CSIZE) { @@ -149,12 +149,12 @@ void ircomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; IRDA_DEBUG(2, "%s()\n", __func__ ); if ((cflag == old_termios->c_cflag) && - (RELEVANT_IFLAG(tty->termios->c_iflag) == + (RELEVANT_IFLAG(tty->termios.c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { return; @@ -173,7 +173,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty, if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { self->settings.dte |= IRCOMM_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { self->settings.dte |= IRCOMM_RTS; } @@ -182,7 +182,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty, /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; ircomm_tty_start(tty); -- cgit v0.10.2 From c97ce276909b0434cd74f9e6c7da37bda59106bb Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 14 Jul 2012 15:32:10 +0100 Subject: f81232: correct stubbed termios handler Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 42c604bc..79451ee 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -177,6 +177,7 @@ static void f81232_set_termios(struct tty_struct *tty, return; /* Do the real work here... */ + tty_termios_copy_hw(&tty->termios, old_termios); } static int f81232_tiocmget(struct tty_struct *tty) -- cgit v0.10.2 From 6a6c8b362be31fd9c1caa776313e0725dbed1cf9 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 14 Jul 2012 15:32:50 +0100 Subject: usb, kobil: Sort out some bogus tty handling Stuff noticed while doing the termios conversion. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 0516a96..bf5c749 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -192,8 +192,8 @@ static void kobil_init_termios(struct tty_struct *tty) { /* Default to echo off and other sane device settings */ tty->termios.c_lflag = 0; - tty->termios.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); - tty->termios.c_lflag = IGNBRK | IGNPAR | IXOFF; + tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); + tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF; /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ tty->termios.c_oflag &= ~ONLCR; } @@ -588,7 +588,7 @@ static void kobil_set_termios(struct tty_struct *tty, if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { /* This device doesn't support ioctl calls */ - tty->termios = *old; + tty_termios_copy_hw(&tty->termios, old); return; } -- cgit v0.10.2 From 9833facf90c625f9757295bda6d970f82132b7be Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 17 Jul 2012 17:05:40 +0100 Subject: tty: Fix up PPC fallout from the termios move This fixes up the problem Stephen Rothwell reported when trying to merge -next Signed-off-by: Alan Cox Reported-by: Stephen Rothwell Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index d3c2bda..12b1fa0 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -738,27 +738,27 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) static void set_sgflags(struct ktermios *termios, int flags) { - termios.c_iflag = ICRNL | IXON; - termios.c_oflag = 0; - termios.c_lflag = ISIG | ICANON; + termios->c_iflag = ICRNL | IXON; + termios->c_oflag = 0; + termios->c_lflag = ISIG | ICANON; if (flags & 0x02) { /* cbreak */ - termios.c_iflag = 0; - termios.c_lflag &= ~ICANON; + termios->c_iflag = 0; + termios->c_lflag &= ~ICANON; } if (flags & 0x08) { /* echo */ - termios.c_lflag |= ECHO | ECHOE | ECHOK | + termios->c_lflag |= ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; } if (flags & 0x10) { /* crmod */ - termios.c_oflag |= OPOST | ONLCR; + termios->c_oflag |= OPOST | ONLCR; } if (flags & 0x20) { /* raw */ - termios.c_iflag = 0; - termios.c_lflag &= ~(ISIG | ICANON); + termios->c_iflag = 0; + termios->c_lflag &= ~(ISIG | ICANON); } - if (!(termios.c_lflag & ICANON)) { - termios.c_cc[VMIN] = 1; - termios.c_cc[VTIME] = 0; + if (!(termios->c_lflag & ICANON)) { + termios->c_cc[VMIN] = 1; + termios->c_cc[VTIME] = 0; } } -- cgit v0.10.2 From ce7240e445303de3ca66e6d08f17a2ec278a5bf6 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 17 Jul 2012 17:06:20 +0100 Subject: 8250: three way resolve of the 8250 diffs This resolves the differences between the original 8250 patch, the revised 8250 patch and the independant clean up of the octeon driver (to use platform devices properly yay!) Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index 1d82d58..164544a 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf, static int register_serial_portandirq(unsigned int port, int irq) { - struct uart_port uart; + struct uart_8250_port uart; switch ( port ) { case 0x3f8: @@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq) } /* switch */ /* irq is okay */ - memset(&uart, 0, sizeof(struct uart_port)); + memset(&uart, 0, sizeof(uart)); - uart.uartclk = 1843200; - uart.iobase = port; - uart.irq = irq; - uart.iotype = UPIO_PORT; - uart.flags = UPF_SHARE_IRQ; - return serial8250_register_port(&uart); + uart.port.uartclk = 1843200; + uart.port.iobase = port; + uart.port.irq = irq; + uart.port.iotype = UPIO_PORT; + uart.port.flags = UPF_SHARE_IRQ; + return serial8250_register_8250_port(&uart); } diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c index 1dcb9ae..01e2b0d 100644 --- a/drivers/misc/ibmasm/uart.c +++ b/drivers/misc/ibmasm/uart.c @@ -33,7 +33,7 @@ void ibmasm_register_uart(struct service_processor *sp) { - struct uart_port uport; + struct uart_8250_port uart; void __iomem *iomem_base; iomem_base = sp->base_address + SCOUT_COM_B_BASE; @@ -47,14 +47,14 @@ void ibmasm_register_uart(struct service_processor *sp) return; } - memset(&uport, 0, sizeof(struct uart_port)); - uport.irq = sp->irq; - uport.uartclk = 3686400; - uport.flags = UPF_SHARE_IRQ; - uport.iotype = UPIO_MEM; - uport.membase = iomem_base; + memset(&uart, 0, sizeof(uart)); + uart.port.irq = sp->irq; + uart.port.uartclk = 3686400; + uart.port.flags = UPF_SHARE_IRQ; + uart.port.iotype = UPIO_MEM; + uart.port.membase = iomem_base; - sp->serial_line = serial8250_register_port(&uport); + sp->serial_line = serial8250_register_8250_port(&uart); if (sp->serial_line < 0) { dev_err(sp->dev, "Failed to register serial port\n"); return; diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index ac149d9..fcb5b0e 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1147,15 +1147,17 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart) { #define COSMISC_CONSTANT 6 - struct uart_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, + 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; @@ -1164,7 +1166,7 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart) uart->iu_scr = COSMISC_CONSTANT, uart->iu_lcr = lcr; uart->iu_lcr; - serial8250_register_port(&port); + serial8250_register_8250_port(&port); } static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index c335b2b..972b521 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -13,36 +13,6 @@ #include -struct uart_8250_port { - struct uart_port port; - struct timer_list timer; /* "no irq" timer */ - struct list_head list; /* ports on this IRQ */ - unsigned short capabilities; /* port capabilities */ - unsigned short bugs; /* port bugs */ - unsigned int tx_loadsz; /* transmit fifo load size */ - unsigned char acr; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned char mcr_mask; /* mask of user bits */ - unsigned char mcr_force; /* mask of forced bits */ - unsigned char cur_iotype; /* Running I/O type */ - - /* - * Some bits in registers are cleared on a read, so they must - * be saved whenever the register is read but the bits will not - * be immediately processed. - */ -#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS - unsigned char lsr_saved_flags; -#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA - unsigned char msr_saved_flags; - - /* 8250 specific callbacks */ - int (*dl_read)(struct uart_8250_port *); - void (*dl_write)(struct uart_8250_port *, int); -}; - struct old_serial_port { unsigned int uart; unsigned int baud_base; diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index afb955f..c3b2ec0 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -141,7 +141,7 @@ static int __devinit dw8250_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no clock-frequency property set\n"); return -EINVAL; } - uart.uart.port.uartclk = val; + uart.port.uartclk = val; data->line = serial8250_register_8250_port(&uart); if (data->line < 0) diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 34e7187..ffc7879 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -144,8 +144,15 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev) switch (port_type) { #ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: - ret = serial8250_register_port(&port); + { + /* For now the of bindings don't support the extra + 8250 specific bits */ + struct uart_8250_port port8250; + memset(&port8250, 0, sizeof(port8250)); + port8250.port = port; + ret = serial8250_register_8250_port(&port8250); break; + } #endif #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL case PORT_NWPSERIAL: diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index f41dcc9..c174c90 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -65,8 +65,36 @@ enum { * platform device. Using these will make your driver * dependent on the 8250 driver. */ -struct uart_port; -struct uart_8250_port; + +struct uart_8250_port { + struct uart_port port; + struct timer_list timer; /* "no irq" timer */ + struct list_head list; /* ports on this IRQ */ + unsigned short capabilities; /* port capabilities */ + unsigned short bugs; /* port bugs */ + unsigned int tx_loadsz; /* transmit fifo load size */ + unsigned char acr; + unsigned char ier; + unsigned char lcr; + unsigned char mcr; + unsigned char mcr_mask; /* mask of user bits */ + unsigned char mcr_force; /* mask of forced bits */ + unsigned char cur_iotype; /* Running I/O type */ + + /* + * Some bits in registers are cleared on a read, so they must + * be saved whenever the register is read but the bits will not + * be immediately processed. + */ +#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS + unsigned char lsr_saved_flags; +#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA + unsigned char msr_saved_flags; + + /* 8250 specific callbacks */ + int (*dl_read)(struct uart_8250_port *); + void (*dl_write)(struct uart_8250_port *, int); +}; int serial8250_register_8250_port(struct uart_8250_port *); void serial8250_unregister_port(int line); -- cgit v0.10.2 From 3db1ddb725dcd9a2bb32be2b64d0688c3e1c4579 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 17 Jul 2012 17:06:41 +0100 Subject: vt: fix the keyboard/led locking We touch the LED from both keyboard callback and direct paths. In one case we've got the lock held way up the call chain and in the other we haven't. This leads to complete insanity so fix it by giving the LED bits their own lock. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 9b4f60a..681765b 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -119,6 +119,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals); static struct input_handler kbd_handler; static DEFINE_SPINLOCK(kbd_event_lock); +static DEFINE_SPINLOCK(led_lock); static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static bool dead_key_next; @@ -984,7 +985,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) * or (ii) whatever pattern of lights people want to show using KDSETLED, * or (iii) specified bits of specified words in kernel memory. */ -unsigned char getledstate(void) +static unsigned char getledstate(void) { return ledstate; } @@ -992,7 +993,7 @@ unsigned char getledstate(void) void setledstate(struct kbd_struct *kbd, unsigned int led) { unsigned long flags; - spin_lock_irqsave(&kbd_event_lock, flags); + spin_lock_irqsave(&led_lock, flags); if (!(led & ~7)) { ledioctl = led; kbd->ledmode = LED_SHOW_IOCTL; @@ -1000,7 +1001,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) kbd->ledmode = LED_SHOW_FLAGS; set_leds(); - spin_unlock_irqrestore(&kbd_event_lock, flags); + spin_unlock_irqrestore(&led_lock, flags); } static inline unsigned char getleds(void) @@ -1051,8 +1052,11 @@ int vt_get_leds(int console, int flag) { struct kbd_struct * kbd = kbd_table + console; int ret; + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); ret = vc_kbd_led(kbd, flag); + spin_unlock_irqrestore(&led_lock, flags); return ret; } @@ -1088,11 +1092,11 @@ void vt_set_led_state(int console, int leds) void vt_kbd_con_start(int console) { struct kbd_struct * kbd = kbd_table + console; -/* unsigned long flags; */ -/* spin_lock_irqsave(&kbd_event_lock, flags); */ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); clr_vc_kbd_led(kbd, VC_SCROLLOCK); set_leds(); -/* spin_unlock_irqrestore(&kbd_event_lock, flags); */ + spin_unlock_irqrestore(&led_lock, flags); } /** @@ -1101,21 +1105,15 @@ void vt_kbd_con_start(int console) * * Handle console stop. This is a wrapper for the VT layer * so that we can keep kbd knowledge internal - * - * FIXME: We eventually need to hold the kbd lock here to protect - * the LED updating. We can't do it yet because fn_hold calls stop_tty - * and start_tty under the kbd_event_lock, while normal tty paths - * don't hold the lock. We probably need to split out an LED lock - * but not during an -rc release! */ void vt_kbd_con_stop(int console) { struct kbd_struct * kbd = kbd_table + console; -/* unsigned long flags; */ -/* spin_lock_irqsave(&kbd_event_lock, flags); */ + unsigned long flags; + spin_lock_irqsave(&led_lock, flags); set_vc_kbd_led(kbd, VC_SCROLLOCK); set_leds(); -/* spin_unlock_irqrestore(&kbd_event_lock, flags); */ + spin_unlock_irqrestore(&led_lock, flags); } /* @@ -1127,7 +1125,12 @@ void vt_kbd_con_stop(int console) */ static void kbd_bh(unsigned long dummy) { - unsigned char leds = getleds(); + unsigned char leds; + unsigned long flags; + + spin_lock_irqsave(&led_lock, flags); + leds = getleds(); + spin_unlock_irqrestore(&led_lock, flags); if (leds != ledstate) { input_handler_for_each_handle(&kbd_handler, &leds, @@ -2032,11 +2035,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) return -EPERM; if (arg & ~0x77) return -EINVAL; - spin_lock_irqsave(&kbd_event_lock, flags); + spin_lock_irqsave(&led_lock, flags); kbd->ledflagstate = (arg & 7); kbd->default_ledflagstate = ((arg >> 4) & 7); set_leds(); - spin_unlock_irqrestore(&kbd_event_lock, flags); + spin_unlock_irqrestore(&led_lock, flags); return 0; /* the ioctls below only set the lights, not the functions */ @@ -2131,8 +2134,10 @@ void vt_reset_keyboard(int console) clr_vc_kbd_mode(kbd, VC_CRLF); kbd->lockstate = 0; kbd->slockstate = 0; + spin_lock(&led_lock); kbd->ledmode = LED_SHOW_FLAGS; kbd->ledflagstate = kbd->default_ledflagstate; + spin_unlock(&led_lock); /* do not do set_leds here because this causes an endless tasklet loop when the keyboard hasn't been initialized yet */ spin_unlock_irqrestore(&kbd_event_lock, flags); diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index af9137db..b7c8cdc 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -65,7 +65,6 @@ struct kbd_struct { extern int kbd_init(void); -extern unsigned char getledstate(void); extern void setledstate(struct kbd_struct *kbd, unsigned int led); extern int do_poke_blanked_console; -- cgit v0.10.2 From 36b3c070d2346c890d690d71f6eab02f8c511137 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 17 Jul 2012 17:06:57 +0100 Subject: tty: Move the handling of the tty release logic Now that we don't have tty->termios tied to drivers->tty we can untangle the logic here. In addition we can push the removal logic out of the destructor path. At that point we can think about sorting out tty_port and console and all the other ugly hangovers. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 5ad7ccc..60c08ce 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -527,12 +527,6 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, return tty; } -static void pty_unix98_shutdown(struct tty_struct *tty) -{ - tty_driver_remove_tty(tty->driver, tty); - /* We have our own method as we don't use the tty index */ -} - /* We have no need to install and remove our tty objects as devpts does all the work for us */ @@ -558,9 +552,8 @@ static const struct tty_operations ptm_unix98_ops = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_unix98_ioctl, - .shutdown = pty_unix98_shutdown, - .cleanup = pty_cleanup, - .resize = pty_resize + .resize = pty_resize, + .cleanup = pty_cleanup }; static const struct tty_operations pty_unix98_ops = { @@ -575,7 +568,6 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .shutdown = pty_unix98_shutdown, .cleanup = pty_cleanup, }; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index cfd12da..be18d60 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1249,16 +1249,16 @@ int tty_init_termios(struct tty_struct *tty) struct ktermios *tp; int idx = tty->index; - tp = tty->driver->termios[idx]; - if (tp == NULL) { - tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); - if (tp == NULL) - return -ENOMEM; - *tp = tty->driver->init_termios; - tty->driver->termios[idx] = tp; + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + tty->termios = tty->driver->init_termios; + else { + /* Check for lazy saved data */ + tp = tty->driver->termios[idx]; + if (tp != NULL) + tty->termios = *tp; + else + tty->termios = tty->driver->init_termios; } - tty->termios = *tp; - /* Compatibility until drivers always set this */ tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); @@ -1437,24 +1437,24 @@ void tty_free_termios(struct tty_struct *tty) { struct ktermios *tp; int idx = tty->index; - /* Kill this flag and push into drivers for locking etc */ - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - /* FIXME: Locking on ->termios array */ - tp = tty->driver->termios[idx]; - tty->driver->termios[idx] = NULL; - kfree(tp); + + /* If the port is going to reset then it has no termios to save */ + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + return; + + /* Stash the termios data */ + tp = tty->driver->termios[idx]; + if (tp == NULL) { + tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); + if (tp == NULL) { + pr_warn("tty: no memory to save termios state.\n"); + return; + } } - else - *tty->driver->termios[idx] = tty->termios; + *tp = tty->termios; } EXPORT_SYMBOL(tty_free_termios); -void tty_shutdown(struct tty_struct *tty) -{ - tty_driver_remove_tty(tty->driver, tty); - tty_free_termios(tty); -} -EXPORT_SYMBOL(tty_shutdown); /** * release_one_tty - release tty structure memory @@ -1498,11 +1498,6 @@ static void queue_release_one_tty(struct kref *kref) { struct tty_struct *tty = container_of(kref, struct tty_struct, kref); - if (tty->ops->shutdown) - tty->ops->shutdown(tty); - else - tty_shutdown(tty); - /* The hangup queue is now free so we can reuse it rather than waste a chunk of memory for each port */ INIT_WORK(&tty->hangup_work, release_one_tty); @@ -1542,6 +1537,11 @@ static void release_tty(struct tty_struct *tty, int idx) /* This should always be true but check for the moment */ WARN_ON(tty->index != idx); + if (tty->ops->shutdown) + tty->ops->shutdown(tty); + tty_free_termios(tty); + tty_driver_remove_tty(tty->driver, tty); + if (tty->link) tty_kref_put(tty->link); tty_kref_put(tty); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index dbceaeb..e07ded3 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2850,7 +2850,6 @@ static void con_shutdown(struct tty_struct *tty) console_lock(); vc->port.tty = NULL; console_unlock(); - tty_shutdown(tty); } static int default_italic_color = 2; // green (ASCII) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 5fe2135..aa4b0d7 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -305,8 +305,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp) * Do the resource freeing and refcount dropping for the port. * Avoid freeing the console. * - * Called asynchronously after the last tty kref is dropped, - * and the tty layer has already done the tty_shutdown(tty); + * Called asynchronously after the last tty kref is dropped. */ static void serial_cleanup(struct tty_struct *tty) { diff --git a/include/linux/tty.h b/include/linux/tty.h index d5e75ee..a39e723 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -423,7 +423,6 @@ extern void tty_unthrottle(struct tty_struct *tty); extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws); extern void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty); -extern void tty_shutdown(struct tty_struct *tty); extern void tty_free_termios(struct tty_struct *tty); extern int is_current_pgrp_orphaned(void); extern struct pid *tty_get_pgrp(struct tty_struct *tty); diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 04419c1..80e72dc 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -45,14 +45,9 @@ * * void (*shutdown)(struct tty_struct * tty); * - * This routine is called synchronously when a particular tty device - * is closed for the last time freeing up the resources. - * Note that tty_shutdown() is not called if ops->shutdown is defined. - * This means one is responsible to take care of calling ops->remove (e.g. - * via tty_driver_remove_tty) and releasing tty->termios. - * Note that this hook may be called from *all* the contexts where one - * uses tty refcounting (e.g. tty_port_tty_get). - * + * This routine is called under the tty lock when a particular tty device + * is closed for the last time. It executes before the tty resources + * are freed so may execute while another function holds a tty kref. * * void (*cleanup)(struct tty_struct * tty); * -- cgit v0.10.2 From fde8be29239bf4a4118d918df1b2b8ef7266b1a2 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 17 Jul 2012 17:08:31 +0100 Subject: tty: of_serial: add no-loopback-test property The loopback test mode is not implemented in all NS16550 compatible UARTs. The 8250 driver uses the UPF_SKIP_TEST flag to indicate this, however it is not possible to set this flag via device-tree. Add a new 'no-loopback-test' property, and modify the of_serial driver to set the UPF_SKIP_TEST flag if the property is present. Signed-off-by: Gabor Juhos Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt index 0847fde..ba385f2 100644 --- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt @@ -25,6 +25,8 @@ Optional properties: accesses to the UART (e.g. TI davinci). - used-by-rtas : set to indicate that the port is in use by the OpenFirmware RTAS and should not be registered. +- no-loopback-test: set to indicate that the port does not implements loopback + test mode Example: diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index ffc7879..df443b9 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -105,6 +105,10 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, port->uartclk = clk; port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; + + if (of_find_property(np, "no-loopback-test", NULL)) + port->flags |= UPF_SKIP_TEST; + port->dev = &ofdev->dev; if (type == PORT_TEGRA) -- cgit v0.10.2 From 669bd45f117cc8c7309acd6b6bb054fe4d9e46c0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 2 Jul 2012 18:51:38 +0100 Subject: pch_uart: Fix missing break for 16 byte fifo Otherwise we fall back to the wrong value. Reported-by: Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=44091 Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d291518..c5bc23d 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1266,6 +1266,7 @@ static int pch_uart_startup(struct uart_port *port) break; case 16: fifo_size = PCH_UART_HAL_FIFO16; + break; case 1: default: fifo_size = PCH_UART_HAL_FIFO_DIS; -- cgit v0.10.2 From ae213f30358e5bf68a05badf059bb4d9115755f5 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 6 Jul 2012 17:19:42 +0900 Subject: pch_uart: Fix rx error interrupt setting issue Rx Error interrupt(E.G. parity error) is not enabled. So, when parity error occurs, error interrupt is not occurred. As a result, the received data is not dropped. This patch adds enable/disable rx error interrupt code. Signed-off-by: Tomoya MORINAGA Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index c5bc23d..2cc9b46 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -757,7 +757,8 @@ static void pch_dma_rx_complete(void *arg) tty_flip_buffer_push(tty); tty_kref_put(tty); async_tx_ack(priv->desc_rx); - pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); } static void pch_dma_tx_complete(void *arg) @@ -812,7 +813,8 @@ static int handle_rx_to(struct eg20t_port *priv) int rx_size; int ret; if (!priv->start_rx) { - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); return 0; } buf = &priv->rxbuf; @@ -1081,11 +1083,13 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) case PCH_UART_IID_RDR: /* Received Data Ready */ if (priv->use_dma) { pch_uart_hal_disable_interrupt(priv, - PCH_UART_HAL_RX_INT); + PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); ret = dma_handle_rx(priv); if (!ret) pch_uart_hal_enable_interrupt(priv, - PCH_UART_HAL_RX_INT); + PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); } else { ret = handle_rx(priv); } @@ -1211,7 +1215,8 @@ static void pch_uart_stop_rx(struct uart_port *port) struct eg20t_port *priv; priv = container_of(port, struct eg20t_port, port); priv->start_rx = 0; - pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); } /* Enable the modem status interrupts. */ @@ -1304,7 +1309,8 @@ static int pch_uart_startup(struct uart_port *port) pch_request_dma(port); priv->start_rx = 1; - pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); + pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT | + PCH_UART_HAL_RX_ERR_INT); uart_update_timeout(port, CS8, default_baud); return 0; -- cgit v0.10.2 From 2fc39aebf682bed97a78d278f6adf6c395700d19 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 6 Jul 2012 17:19:43 +0900 Subject: pch_uart: Fix parity setting issue Parity Setting value is reverse. E.G. In case of setting ODD parity, EVEN value is set. This patch inverts "if" condition. Signed-off-by: Tomoya MORINAGA Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 2cc9b46..558ce85 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1368,7 +1368,7 @@ static void pch_uart_set_termios(struct uart_port *port, stb = PCH_UART_HAL_STB1; if (termios->c_cflag & PARENB) { - if (!(termios->c_cflag & PARODD)) + if (termios->c_cflag & PARODD) parity = PCH_UART_HAL_PARITY_ODD; else parity = PCH_UART_HAL_PARITY_EVEN; -- cgit v0.10.2 From 373f5aedbc6fb73d30f00eeb0dc7313ecfede908 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 19 Jul 2012 12:23:28 +0100 Subject: pcmcia,synclink_cs: fix termios port I missed Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 0a484b4..d0cbd29 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1344,7 +1344,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty) /* TODO:disable interrupts instead of reset to preserve signal states */ reset_device(info); - if (!tty || tty->termios->c_cflag & HUPCL) { + if (!tty || tty->termios.c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } @@ -1385,7 +1385,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty) port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); get_signals(info); - if (info->netcount || (tty && (tty->termios->c_cflag & CREAD))) + if (info->netcount || (tty && (tty->termios.c_cflag & CREAD))) rx_start(info); spin_unlock_irqrestore(&info->lock,flags); @@ -1398,14 +1398,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty) unsigned cflag; int bits_per_char; - if (!tty || !tty->termios) + if (!tty) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ @@ -1728,7 +1728,7 @@ static void mgslpc_throttle(struct tty_struct * tty) if (I_IXOFF(tty)) mgslpc_send_xchar(tty, STOP_CHAR(tty)); - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals &= ~SerialSignal_RTS; set_signals(info); @@ -1757,7 +1757,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty) mgslpc_send_xchar(tty, START_CHAR(tty)); } - if (tty->termios->c_cflag & CRTSCTS) { + if (tty->termios.c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS; set_signals(info); @@ -2293,8 +2293,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term tty->driver->name ); /* just return if nothing has changed */ - if ((tty->termios->c_cflag == old_termios->c_cflag) - && (RELEVANT_IFLAG(tty->termios->c_iflag) + if ((tty->termios.c_cflag == old_termios->c_cflag) + && (RELEVANT_IFLAG(tty->termios.c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) return; @@ -2302,7 +2302,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term /* Handle transition to B0 status */ if (old_termios->c_cflag & CBAUD && - !(tty->termios->c_cflag & CBAUD)) { + !(tty->termios.c_cflag & CBAUD)) { info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); spin_lock_irqsave(&info->lock,flags); set_signals(info); @@ -2311,9 +2311,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && - tty->termios->c_cflag & CBAUD) { + tty->termios.c_cflag & CBAUD) { info->serial_signals |= SerialSignal_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) { info->serial_signals |= SerialSignal_RTS; } @@ -2324,7 +2324,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term /* Handle turning off CRTSCTS */ if (old_termios->c_cflag & CRTSCTS && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; tx_release(tty); } -- cgit v0.10.2 From d155255a344c417acad74156654295a2964e6b81 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 27 Jul 2012 18:02:54 +0100 Subject: tty: Fix race in tty release Ian Abbott found that the tty layer would explode with the right set of parallel open and close operations. This is because we race in the handling of tty->drivers->termios[]. Correct this by Making tty_ldisc_release behave like nromal code (takes the lock, does stuff, drops the lock) Drop the tty lock earlier in tty_ldisc_release Taking the tty mutex around the driver->termios update in all cases Adding a WARN_ON to catch future screwups. I also forgot to clean up the pty resources properly. With a pty pair we need to pull both halves out of the tables. Signed-off-by: Alan Cox Tested-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 60c08ce..d6579a9 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -282,6 +282,17 @@ done: return 0; } +/** + * pty_common_install - set up the pty pair + * @driver: the pty driver + * @tty: the tty being instantiated + * @bool: legacy, true if this is BSD style + * + * Perform the initial set up for the tty/pty pair. Called from the + * tty layer when the port is first opened. + * + * Locking: the caller must hold the tty_mutex + */ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, bool legacy) { @@ -364,6 +375,14 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty) return pty_common_install(driver, tty, true); } +static void pty_remove(struct tty_driver *driver, struct tty_struct *tty) +{ + struct tty_struct *pair = tty->link; + driver->ttys[tty->index] = NULL; + if (pair) + pair->driver->ttys[pair->index] = NULL; +} + static int pty_bsd_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -395,7 +414,8 @@ static const struct tty_operations master_pty_ops_bsd = { .set_termios = pty_set_termios, .ioctl = pty_bsd_ioctl, .cleanup = pty_cleanup, - .resize = pty_resize + .resize = pty_resize, + .remove = pty_remove }; static const struct tty_operations slave_pty_ops_bsd = { @@ -409,7 +429,8 @@ static const struct tty_operations slave_pty_ops_bsd = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .cleanup = pty_cleanup, - .resize = pty_resize + .resize = pty_resize, + .remove = pty_remove }; static void __init legacy_pty_init(void) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index be18d60..c6f4d71 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1465,7 +1465,6 @@ EXPORT_SYMBOL(tty_free_termios); * in use. It also gets called when setup of a device fails. * * Locking: - * tty_mutex - sometimes only * takes the file list lock internally when working on the list * of ttys that the driver keeps. * @@ -1526,17 +1525,16 @@ EXPORT_SYMBOL(tty_kref_put); * and decrement the refcount of the backing module. * * Locking: - * tty_mutex - sometimes only + * tty_mutex * takes the file list lock internally when working on the list * of ttys that the driver keeps. - * FIXME: should we require tty_mutex is held here ?? * */ static void release_tty(struct tty_struct *tty, int idx) { /* This should always be true but check for the moment */ WARN_ON(tty->index != idx); - + WARN_ON(!mutex_is_locked(&tty_mutex)); if (tty->ops->shutdown) tty->ops->shutdown(tty); tty_free_termios(tty); @@ -1708,6 +1706,9 @@ int tty_release(struct inode *inode, struct file *filp) * The closing flags are now consistent with the open counts on * both sides, and we've completed the last operation that could * block, so it's safe to proceed with closing. + * + * We must *not* drop the tty_mutex until we ensure that a further + * entry into tty_open can not pick up this tty. */ if (pty_master) { if (--o_tty->count < 0) { @@ -1759,12 +1760,13 @@ int tty_release(struct inode *inode, struct file *filp) } mutex_unlock(&tty_mutex); + tty_unlock(); + /* At this point the TTY_CLOSING flag should ensure a dead tty + cannot be re-opened by a racing opener */ /* check whether both sides are closing ... */ - if (!tty_closing || (o_tty && !o_tty_closing)) { - tty_unlock(); + if (!tty_closing || (o_tty && !o_tty_closing)) return 0; - } #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__); @@ -1777,12 +1779,14 @@ int tty_release(struct inode *inode, struct file *filp) * The release_tty function takes care of the details of clearing * the slots and preserving the termios structure. */ + mutex_lock(&tty_mutex); release_tty(tty, idx); + mutex_unlock(&tty_mutex); /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - tty_unlock(); + return 0; } diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index e6156c6..3d06871 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -912,7 +912,6 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * race with the set_ldisc code path. */ - tty_unlock(); tty_ldisc_halt(tty); tty_ldisc_flush_works(tty); tty_lock(); @@ -930,6 +929,8 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) tty_set_termios_ldisc(tty, N_TTY); mutex_unlock(&tty->ldisc_mutex); + tty_unlock(); + /* This will need doing differently if we need to lock */ if (o_tty) tty_ldisc_release(o_tty, NULL); -- cgit v0.10.2 From 367e43c50d7f7c3b0cec17f4d855a96f47f5e17b Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 10 Aug 2012 11:55:11 +0200 Subject: link-vmlinux.sh: Fix stray "echo" in error message Reported-by: Jan Engelhardt Signed-off-by: Michal Marek diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 4629038..4235a63 100644 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -211,7 +211,7 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then if ! cmp -s System.map .tmp_System.map; then echo >&2 Inconsistent kallsyms data - echo >&2 echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround + echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround cleanup exit 1 fi -- cgit v0.10.2 From 2d8a1001ee0e961a00ab460ff54ea9a321a56d2e Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 20 Jul 2012 14:58:31 +1000 Subject: tty: fix up usb serial console for termios change. fixes these errors: drivers/usb/serial/console.c: In function 'usb_console_setup': drivers/usb/serial/console.c:168:16: error: invalid type argument of '->' (have 'struct ktermios') drivers/usb/serial/console.c:169:4: error: incompatible type for argument 1 of 'tty_termios_encode_baud_rate' include/linux/tty.h:449:13: note: expected 'struct ktermios *' but argument is of type 'struct ktermios' Signed-off-by: Stephen Rothwell Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index b9cca6d..9a56428 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -165,8 +165,8 @@ static int usb_console_setup(struct console *co, char *options) } if (serial->type->set_termios) { - tty->termios->c_cflag = cflag; - tty_termios_encode_baud_rate(tty->termios, baud, baud); + tty->termios.c_cflag = cflag; + tty_termios_encode_baud_rate(&tty->termios, baud, baud); memset(&dummy, 0, sizeof(struct ktermios)); serial->type->set_termios(tty, port, &dummy); -- cgit v0.10.2 From 9b12daf70815364d07bc0bbac41468098264f782 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 23 Jul 2012 12:35:44 +0100 Subject: serqt_usb2: drag screaming into the 21st century Fix the termios stuff but while we are at it do something about the rest of it Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index 8a362f7..c90de96 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -315,10 +315,8 @@ static void qt_read_bulk_callback(struct urb *urb) } tty = tty_port_tty_get(&port->port); - if (!tty) { - dbg("%s - bad tty pointer - exiting", __func__); + if (!tty) return; - } data = urb->transfer_buffer; @@ -364,7 +362,7 @@ static void qt_read_bulk_callback(struct urb *urb) goto exit; } - if (tty && RxCount) { + if (RxCount) { flag_data = 0; for (i = 0; i < RxCount; ++i) { /* Look ahead code here */ @@ -428,7 +426,7 @@ static void qt_read_bulk_callback(struct urb *urb) dbg("%s - failed resubmitting read urb, error %d", __func__, result); else { - if (tty && RxCount) { + if (RxCount) { tty_flip_buffer_push(tty); tty_schedule_flip(tty); } @@ -897,8 +895,6 @@ static int qt_open(struct tty_struct *tty, * Put this here to make it responsive to stty and defaults set by * the tty layer */ - /* FIXME: is this needed? */ - /* qt_set_termios(tty, port, NULL); */ /* Check to see if we've set up our endpoint info yet */ if (port0->open_ports == 1) { @@ -1195,7 +1191,7 @@ static void qt_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - struct ktermios *termios = tty->termios; + struct ktermios *termios = &tty->termios; unsigned char new_LCR = 0; unsigned int cflag = termios->c_cflag; unsigned int index; @@ -1204,7 +1200,7 @@ static void qt_set_termios(struct tty_struct *tty, index = tty->index - port->serial->minor; - switch (cflag) { + switch (cflag & CSIZE) { case CS5: new_LCR |= SERIAL_5_DATA; break; @@ -1215,6 +1211,8 @@ static void qt_set_termios(struct tty_struct *tty, new_LCR |= SERIAL_7_DATA; break; default: + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; case CS8: new_LCR |= SERIAL_8_DATA; break; @@ -1301,7 +1299,7 @@ static void qt_set_termios(struct tty_struct *tty, dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n"); } - tty->termios->c_cflag &= ~CMSPAR; + termios->c_cflag &= ~CMSPAR; /* FIXME: Error cases should be returning the actual bits changed only */ } -- cgit v0.10.2 From 6b9563a714138dc2377c500e588e31f7166c92f0 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 24 Jul 2012 10:59:01 +0100 Subject: tty: fix the metro-usb change I messed up Fixes the leak of a tty kref that Jiri pointed out. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 7ae9af6..2b0627b 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -136,8 +136,8 @@ static void metrousb_read_int_callback(struct urb *urb) /* Force the data to the tty layer. */ tty_flip_buffer_push(tty); - tty_kref_put(tty); } + tty_kref_put(tty); /* Set any port variables. */ spin_lock_irqsave(&metro_priv->lock, flags); -- cgit v0.10.2 From 4ac5d7050e4e4d63751e78fb152a274d05c08563 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Jul 2012 12:51:52 +0100 Subject: tty: fix missing assignment We're trying to save the termios state and we need to allocate a buffer to do it. Smatch complains that the buffer is leaked at the end of the function. Signed-off-by: Dan Carpenter Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c6f4d71..6087499 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1450,6 +1450,7 @@ void tty_free_termios(struct tty_struct *tty) pr_warn("tty: no memory to save termios state.\n"); return; } + tty->driver->termios[idx] = tp; } *tp = tty->termios; } -- cgit v0.10.2 From dc6802a771e91050fb686dfeeb9de4c6c9cadb79 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Jul 2012 12:52:04 +0100 Subject: tty: handle NULL parameters in free_tty_struct() We sometimes pass NULL pointers to free_tty_struct(). One example where it can happen is in the error handling code in pty_common_install(). Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 6087499..6784aae 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -181,6 +181,8 @@ struct tty_struct *alloc_tty_struct(void) void free_tty_struct(struct tty_struct *tty) { + if (!tty) + return; if (tty->dev) put_device(tty->dev); kfree(tty->write_buf); -- cgit v0.10.2 From 89c8d91e31f267703e365593f6bfebb9f6d2ad01 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 8 Aug 2012 16:30:13 +0100 Subject: tty: localise the lock The termios and other changes mean the other protections needed on the driver tty arrays should be adequate. Turn it all back on. This contains pieces folded in from the fixes made to the original patches | From: Geert Uytterhoeven (fix m68k) | From: Paul Gortmaker (fix cris) | From: Jiri Kosina (lockdep) | From: Eric Dumazet (lockdep) Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 0e8441e..998731f 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - tty_lock(); + tty_lock(tty); tmp.line = tty->index; tmp.port = state->port; tmp.flags = state->tport.flags; @@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state, tmp.close_delay = state->tport.close_delay; tmp.closing_wait = state->tport.closing_wait; tmp.custom_divisor = state->custom_divisor; - tty_unlock(); + tty_unlock(tty); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; - tty_lock(); + tty_lock(tty); change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || new_serial.custom_divisor != state->custom_divisor; if (new_serial.irq || new_serial.port != state->port || new_serial.xmit_fifo_size != state->xmit_fifo_size) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, (new_serial.xmit_fifo_size != state->xmit_fifo_size) || ((new_serial.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { - tty_unlock(); + tty_unlock(tty); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | @@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state, } if (new_serial.baud_base < 9600) { - tty_unlock(); + tty_unlock(tty); return -EINVAL; } @@ -1116,7 +1116,7 @@ check_and_exit: } } else retval = startup(tty, state); - tty_unlock(); + tty_unlock(tty); return retval; } diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index e77db71..c8850ea 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->port.close_wait, + wait_event_interruptible_tty(tty, info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 5c6c314..1e64050 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); - tty_lock(); + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1077,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, goto unlock; } /* block until there is a message: */ - wait_event_interruptible_tty(pInfo->read_wait, + wait_event_interruptible_tty(tty, pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } @@ -1107,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, } ret = -EPERM; unlock: - tty_unlock(); + tty_unlock(tty); return ret; } @@ -1156,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; - tty_lock(); + tty_lock(tty); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1175,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); - tty_unlock(); + tty_unlock(tty); return 0; } diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index d6579a9..4399f1d 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -47,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); tty->packet = 0; + /* Review - krefs on tty_link ?? */ if (!tty->link) return; tty->link->packet = 0; @@ -62,9 +63,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&devpts_mutex); } #endif - tty_unlock(); + tty_unlock(tty); tty_vhangup(tty->link); - tty_lock(); + tty_lock(tty); } } @@ -617,26 +618,27 @@ static int ptmx_open(struct inode *inode, struct file *filp) return retval; /* find a device that is not in use. */ - tty_lock(); + mutex_lock(&devpts_mutex); index = devpts_new_index(inode); - tty_unlock(); if (index < 0) { retval = index; goto err_file; } + mutex_unlock(&devpts_mutex); + mutex_lock(&tty_mutex); - mutex_lock(&devpts_mutex); tty = tty_init_dev(ptm_driver, index); - mutex_unlock(&devpts_mutex); - tty_lock(); - mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { retval = PTR_ERR(tty); goto out; } + /* The tty returned here is locked so we can safely + drop the mutex */ + mutex_unlock(&tty_mutex); + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty_add_file(tty, filp); @@ -649,16 +651,17 @@ static int ptmx_open(struct inode *inode, struct file *filp) if (retval) goto err_release; - tty_unlock(); + tty_unlock(tty); return 0; err_release: - tty_unlock(); + tty_unlock(tty); tty_release(inode, filp); return retval; out: + mutex_unlock(&tty_mutex); devpts_kill_index(inode, index); - tty_unlock(); err_file: + mutex_unlock(&devpts_mutex); tty_free_file(filp); return retval; } diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 6b705b2..a770b10 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) @@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); #endif - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); @@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp) */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { - wait_event_interruptible_tty(info->close_wait, + wait_event_interruptible_tty(tty, info->close_wait, !(info->flags & ASYNC_CLOSING)); #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index bdeeb31..991bae8 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("%s(%d):block_til_ready blocking on %s count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index f02d18a..9130253 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index ae75a3c..95fd4e2 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, printk("%s(%d):%s block_til_ready() count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 6784aae..6902244 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -187,6 +187,7 @@ void free_tty_struct(struct tty_struct *tty) put_device(tty->dev); kfree(tty->write_buf); tty_buffer_free_all(tty); + tty->magic = 0xDEADDEAD; kfree(tty); } @@ -575,7 +576,7 @@ void __tty_hangup(struct tty_struct *tty) } spin_unlock(&redirect_lock); - tty_lock(); + tty_lock(tty); /* some functions below drop BTM, so we need this bit */ set_bit(TTY_HUPPING, &tty->flags); @@ -668,7 +669,7 @@ void __tty_hangup(struct tty_struct *tty) clear_bit(TTY_HUPPING, &tty->flags); tty_ldisc_enable(tty); - tty_unlock(); + tty_unlock(tty); if (f) fput(f); @@ -1105,12 +1106,12 @@ void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { mutex_lock(&tty->atomic_write_lock); - tty_lock(); + tty_lock(tty); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { - tty_unlock(); + tty_unlock(tty); tty->ops->write(tty, msg, strlen(msg)); } else - tty_unlock(); + tty_unlock(tty); tty_write_unlock(tty); } return; @@ -1403,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) } initialize_tty_struct(tty, driver, idx); + tty_lock(tty); retval = tty_driver_install_tty(driver, tty); if (retval < 0) goto err_deinit_tty; @@ -1418,9 +1420,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) retval = tty_ldisc_setup(tty, tty->link); if (retval) goto err_release_tty; + /* Return the tty locked so that it cannot vanish under the caller */ return tty; err_deinit_tty: + tty_unlock(tty); deinitialize_tty_struct(tty); free_tty_struct(tty); err_module_put: @@ -1429,6 +1433,7 @@ err_module_put: /* call the tty release_tty routine to clean out this slot */ err_release_tty: + tty_unlock(tty); printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); @@ -1622,7 +1627,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty_paranoia_check(tty, inode, __func__)) return 0; - tty_lock(); + tty_lock(tty); check_tty_count(tty, __func__); __tty_fasync(-1, filp, 0); @@ -1631,10 +1636,11 @@ int tty_release(struct inode *inode, struct file *filp) pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; + /* Review: parallel close */ o_tty = tty->link; if (tty_release_checks(tty, o_tty, idx)) { - tty_unlock(); + tty_unlock(tty); return 0; } @@ -1646,7 +1652,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(); + tty_unlock(tty); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1669,7 +1675,7 @@ int tty_release(struct inode *inode, struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); - tty_lock(); + tty_lock_pair(tty, o_tty); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1700,7 +1706,7 @@ int tty_release(struct inode *inode, struct file *filp) printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", __func__, tty_name(tty, buf)); - tty_unlock(); + tty_unlock_pair(tty, o_tty); mutex_unlock(&tty_mutex); schedule(); } @@ -1763,7 +1769,7 @@ int tty_release(struct inode *inode, struct file *filp) } mutex_unlock(&tty_mutex); - tty_unlock(); + tty_unlock_pair(tty, o_tty); /* At this point the TTY_CLOSING flag should ensure a dead tty cannot be re-opened by a racing opener */ @@ -1780,7 +1786,9 @@ int tty_release(struct inode *inode, struct file *filp) tty_ldisc_release(tty, o_tty); /* * The release_tty function takes care of the details of clearing - * the slots and preserving the termios structure. + * the slots and preserving the termios structure. The tty_unlock_pair + * should be safe as we keep a kref while the tty is locked (so the + * unlock never unlocks a freed tty). */ mutex_lock(&tty_mutex); release_tty(tty, idx); @@ -1789,7 +1797,6 @@ int tty_release(struct inode *inode, struct file *filp) /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - return 0; } @@ -1893,6 +1900,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. * tty->count should protect the rest. * ->siglock protects ->signal/->sighand + * + * Note: the tty_unlock/lock cases without a ref are only safe due to + * tty_mutex */ static int tty_open(struct inode *inode, struct file *filp) @@ -1916,8 +1926,7 @@ retry_open: retval = 0; mutex_lock(&tty_mutex); - tty_lock(); - + /* This is protected by the tty_mutex */ tty = tty_open_current_tty(device, filp); if (IS_ERR(tty)) { retval = PTR_ERR(tty); @@ -1938,17 +1947,19 @@ retry_open: } if (tty) { + tty_lock(tty); retval = tty_reopen(tty); - if (retval) + if (retval < 0) { + tty_unlock(tty); tty = ERR_PTR(retval); - } else + } + } else /* Returns with the tty_lock held for now */ tty = tty_init_dev(driver, index); mutex_unlock(&tty_mutex); if (driver) tty_driver_kref_put(driver); if (IS_ERR(tty)) { - tty_unlock(); retval = PTR_ERR(tty); goto err_file; } @@ -1977,7 +1988,7 @@ retry_open: printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, retval, tty->name); #endif - tty_unlock(); /* need to call tty_release without BTM */ + tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) return retval; @@ -1989,17 +2000,15 @@ retry_open: /* * Need to reset f_op in case a hangup happened. */ - tty_lock(); if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; - tty_unlock(); goto retry_open; } - tty_unlock(); + tty_unlock(tty); mutex_lock(&tty_mutex); - tty_lock(); + tty_lock(tty); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -2007,11 +2016,10 @@ retry_open: tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); - tty_unlock(); + tty_unlock(tty); mutex_unlock(&tty_mutex); return 0; err_unlock: - tty_unlock(); mutex_unlock(&tty_mutex); /* after locks to avoid deadlock */ if (!IS_ERR_OR_NULL(driver)) @@ -2094,10 +2102,13 @@ out: static int tty_fasync(int fd, struct file *filp, int on) { + struct tty_struct *tty = file_tty(filp); int retval; - tty_lock(); + + tty_lock(tty); retval = __tty_fasync(fd, filp, on); - tty_unlock(); + tty_unlock(tty); + return retval; } @@ -2934,6 +2945,7 @@ void initialize_tty_struct(struct tty_struct *tty, tty->pgrp = NULL; tty->overrun_time = jiffies; tty_buffer_init(tty); + mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); init_waitqueue_head(&tty->write_wait); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 3d06871..4d7b562 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -568,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); - tty_lock(); + tty_lock(tty); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. @@ -582,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { - tty_unlock(); + tty_unlock(tty); tty_ldisc_put(new_ldisc); return 0; } - tty_unlock(); + tty_unlock(tty); /* * Problem: What do we do if this blocks ? * We could deadlock here @@ -595,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_wait_until_sent(tty, 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* @@ -605,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); wait_event(tty_ldisc_wait, test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); } @@ -623,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) o_ldisc = tty->ldisc; - tty_unlock(); + tty_unlock(tty); /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -650,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) retval = tty_ldisc_wait_idle(tty, 5 * HZ); - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* handle wait idle failure locked */ @@ -665,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); - tty_unlock(); + tty_unlock(tty); return -EIO; } @@ -708,7 +708,7 @@ enable: if (o_work) schedule_work(&o_tty->buf.work); mutex_unlock(&tty->ldisc_mutex); - tty_unlock(); + tty_unlock(tty); return retval; } @@ -816,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty) * need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); - tty_unlock(); + tty_unlock(tty); cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: - tty_lock(); + tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* At this point we have a closed ldisc and we want to @@ -831,7 +831,7 @@ retry: if (atomic_read(&tty->ldisc->users) != 1) { char cur_n[TASK_COMM_LEN], tty_n[64]; long timeout = 3 * HZ; - tty_unlock(); + tty_unlock(tty); while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { timeout = MAX_SCHEDULE_TIMEOUT; @@ -894,6 +894,23 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) tty_ldisc_enable(tty); return 0; } + +static void tty_ldisc_kill(struct tty_struct *tty) +{ + mutex_lock(&tty->ldisc_mutex); + /* + * Now kill off the ldisc + */ + tty_ldisc_close(tty, tty->ldisc); + tty_ldisc_put(tty->ldisc); + /* Force an oops if we mess this up */ + tty->ldisc = NULL; + + /* Ensure the next open requests the N_TTY ldisc */ + tty_set_termios_ldisc(tty, N_TTY); + mutex_unlock(&tty->ldisc_mutex); +} + /** * tty_ldisc_release - release line discipline * @tty: tty being shut down @@ -912,29 +929,21 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * race with the set_ldisc code path. */ + tty_lock_pair(tty, o_tty); tty_ldisc_halt(tty); tty_ldisc_flush_works(tty); - tty_lock(); - - mutex_lock(&tty->ldisc_mutex); - /* - * Now kill off the ldisc - */ - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - /* Force an oops if we mess this up */ - tty->ldisc = NULL; - - /* Ensure the next open requests the N_TTY ldisc */ - tty_set_termios_ldisc(tty, N_TTY); - mutex_unlock(&tty->ldisc_mutex); - - tty_unlock(); + if (o_tty) { + tty_ldisc_halt(o_tty); + tty_ldisc_flush_works(o_tty); + } /* This will need doing differently if we need to lock */ + tty_ldisc_kill(tty); + if (o_tty) - tty_ldisc_release(o_tty, NULL); + tty_ldisc_kill(o_tty); + tty_unlock_pair(tty, o_tty); /* And the memory resources remaining (buffers, termios) will be disposed of when the kref hits zero */ } diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 9ff986c..67feac9 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,29 +4,70 @@ #include #include -/* - * The 'big tty mutex' - * - * This mutex is taken and released by tty_lock() and tty_unlock(), - * replacing the older big kernel lock. - * It can no longer be taken recursively, and does not get - * released implicitly while sleeping. - * - * Don't use in new code. - */ -static DEFINE_MUTEX(big_tty_mutex); +/* Legacy tty mutex glue */ + +enum { + TTY_MUTEX_NORMAL, + TTY_MUTEX_NESTED, +}; /* * Getting the big tty mutex. */ -void __lockfunc tty_lock(void) + +static void __lockfunc tty_lock_nested(struct tty_struct *tty, + unsigned int subclass) { - mutex_lock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "L Bad %p\n", tty); + WARN_ON(1); + return; + } + tty_kref_get(tty); + mutex_lock_nested(&tty->legacy_mutex, subclass); +} + +void __lockfunc tty_lock(struct tty_struct *tty) +{ + return tty_lock_nested(tty, TTY_MUTEX_NORMAL); } EXPORT_SYMBOL(tty_lock); -void __lockfunc tty_unlock(void) +void __lockfunc tty_unlock(struct tty_struct *tty) { - mutex_unlock(&big_tty_mutex); + if (tty->magic != TTY_MAGIC) { + printk(KERN_ERR "U Bad %p\n", tty); + WARN_ON(1); + return; + } + mutex_unlock(&tty->legacy_mutex); + tty_kref_put(tty); } EXPORT_SYMBOL(tty_unlock); + +/* + * Getting the big tty mutex for a pair of ttys with lock ordering + * On a non pty/tty pair tty2 can be NULL which is just fine. + */ +void __lockfunc tty_lock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + if (tty < tty2) { + tty_lock(tty); + tty_lock_nested(tty2, TTY_MUTEX_NESTED); + } else { + if (tty2 && tty2 != tty) + tty_lock(tty2); + tty_lock_nested(tty, TTY_MUTEX_NESTED); + } +} +EXPORT_SYMBOL(tty_lock_pair); + +void __lockfunc tty_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + tty_unlock(tty); + if (tty2 && tty2 != tty) + tty_unlock(tty2); +} +EXPORT_SYMBOL(tty_unlock_pair); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index edcb827..5246763 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -239,7 +239,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(port->close_wait, + wait_event_interruptible_tty(tty, port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -305,9 +305,9 @@ int tty_port_block_til_ready(struct tty_port *port, retval = -ERESTARTSYS; break; } - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } finish_wait(&port->open_wait, &wait); diff --git a/include/linux/tty.h b/include/linux/tty.h index a39e723..acca24b 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -268,6 +268,7 @@ struct tty_struct { struct mutex ldisc_mutex; struct tty_ldisc *ldisc; + struct mutex legacy_mutex; struct mutex termios_mutex; spinlock_t ctrl_lock; /* Termios values are protected by the termios mutex */ @@ -609,8 +610,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty, /* tty_mutex.c */ /* functions for preparation of BKL removal */ -extern void __lockfunc tty_lock(void) __acquires(tty_lock); -extern void __lockfunc tty_unlock(void) __releases(tty_lock); +extern void __lockfunc tty_lock(struct tty_struct *tty); +extern void __lockfunc tty_unlock(struct tty_struct *tty); +extern void __lockfunc tty_lock_pair(struct tty_struct *tty, + struct tty_struct *tty2); +extern void __lockfunc tty_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2); /* * this shall be called only from where BTM is held (like close) @@ -625,9 +630,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock); static inline void tty_wait_until_sent_from_close(struct tty_struct *tty, long timeout) { - tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */ + tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */ tty_wait_until_sent(tty, timeout); - tty_lock(); + tty_lock(tty); } /* @@ -642,16 +647,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty, * * Do not use in new code. */ -#define wait_event_interruptible_tty(wq, condition) \ +#define wait_event_interruptible_tty(tty, wq, condition) \ ({ \ int __ret = 0; \ if (!(condition)) { \ - __wait_event_interruptible_tty(wq, condition, __ret); \ + __wait_event_interruptible_tty(tty, wq, condition, __ret); \ } \ __ret; \ }) -#define __wait_event_interruptible_tty(wq, condition, ret) \ +#define __wait_event_interruptible_tty(tty, wq, condition, ret) \ do { \ DEFINE_WAIT(__wait); \ \ @@ -660,9 +665,9 @@ do { \ if (condition) \ break; \ if (!signal_pending(current)) { \ - tty_unlock(); \ + tty_unlock(tty); \ schedule(); \ - tty_lock(); \ + tty_lock(tty); \ continue; \ } \ ret = -ERESTARTSYS; \ diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 87ddd05..b54c86a 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -705,9 +705,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) break; } - tty_unlock(); + tty_unlock(tty); schedule(); - tty_lock(); + tty_lock(tty); } set_current_state(TASK_RUNNING); remove_wait_queue(&dev->wait, &wait); -- cgit v0.10.2 From 857196e2758f01ec40f93429013963ca5f22cbae Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 26 Jul 2012 19:00:51 +0100 Subject: ipoctal: make it compile with the termios changes Also fix the silly speed setting bug. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c index fd0e301..394f5de 100644 --- a/drivers/staging/ipack/devices/ipoctal.c +++ b/drivers/staging/ipack/devices/ipoctal.c @@ -617,7 +617,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, struct ipoctal *ipoctal = tty->driver_data; speed_t baud; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; /* Disable and reset everything before change the setup */ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, @@ -643,7 +643,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, default: mr1 |= MR1_CHRL_8_BITS; /* By default, select CS8 */ - tty->termios->c_cflag = (cflag & ~CSIZE) | CS8; + tty->termios.c_cflag = (cflag & ~CSIZE) | CS8; break; } @@ -657,7 +657,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, mr1 |= MR1_PARITY_OFF; /* Mark or space parity is not supported */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; /* Set stop bits */ if (cflag & CSTOPB) @@ -690,10 +690,10 @@ static void ipoctal_set_termios(struct tty_struct *tty, } baud = tty_get_baud_rate(tty); - tty_termios_encode_baud_rate(tty->termios, baud, baud); + tty_termios_encode_baud_rate(&tty->termios, baud, baud); /* Set baud rate */ - switch (tty->termios->c_ospeed) { + switch (baud) { case 75: csr |= TX_CLK_75 | RX_CLK_75; break; @@ -734,7 +734,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, default: csr |= TX_CLK_38400 | RX_CLK_38400; /* In case of default, we establish 38400 bps */ - tty_termios_encode_baud_rate(tty->termios, 38400, 38400); + tty_termios_encode_baud_rate(&tty->termios, 38400, 38400); break; } -- cgit v0.10.2 From 00aaae033e323af33740e7012a8ba4b0fa6dce20 Mon Sep 17 00:00:00 2001 From: Stanislav Kozina Date: Thu, 9 Aug 2012 14:48:58 +0100 Subject: tty: Fix possible race in n_tty_read() Fix possible panic caused by unlocked access to tty->read_cnt in while-loop condition in n_tty_read(). Signed-off-by: Stanislav Kozina Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 101790c..20de673 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1838,13 +1838,13 @@ do_it_again: if (tty->icanon && !L_EXTPROC(tty)) { /* N.B. avoid overrun if nr == 0 */ + spin_lock_irqsave(&tty->read_lock, flags); while (nr && tty->read_cnt) { int eol; eol = test_and_clear_bit(tty->read_tail, tty->read_flags); c = tty->read_buf[tty->read_tail]; - spin_lock_irqsave(&tty->read_lock, flags); tty->read_tail = ((tty->read_tail+1) & (N_TTY_BUF_SIZE-1)); tty->read_cnt--; @@ -1862,15 +1862,19 @@ do_it_again: if (tty_put_user(tty, c, b++)) { retval = -EFAULT; b--; + spin_lock_irqsave(&tty->read_lock, flags); break; } nr--; } if (eol) { tty_audit_push(tty); + spin_lock_irqsave(&tty->read_lock, flags); break; } + spin_lock_irqsave(&tty->read_lock, flags); } + spin_unlock_irqrestore(&tty->read_lock, flags); if (retval) break; } else { -- cgit v0.10.2 From 090abf7b91645c1936ba959b1e1cd6d09110779c Mon Sep 17 00:00:00 2001 From: Jaeden Amero Date: Fri, 27 Jul 2012 08:43:11 -0500 Subject: n_tty: Don't lose characters when PARMRK is enabled When PARMRK is set and large transfers of characters that will get marked are being received, n_tty could drop data silently (i.e. without reporting any error to the client). This is because characters have the potential to take up to three bytes in the line discipline (when they get marked with parity or framing errors), but the amount of free space reported to tty_buffer flush_to_ldisc (via tty->receive_room) is based on the pre-marked data size. With this patch, the n_tty layer will no longer assume that each byte will only take up one byte in the line discipline. Instead, it will make an overly conservative estimate that each byte will take up three bytes in the line discipline when PARMRK is set. Signed-off-by: Jaeden Amero Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 20de673..6259242 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -92,10 +92,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static void n_tty_set_room(struct tty_struct *tty) { - /* tty->read_cnt is not read locked ? */ - int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + int left; int old_left; + /* tty->read_cnt is not read locked ? */ + if (I_PARMRK(tty)) { + /* Multiply read_cnt by 3, since each byte might take up to + * three times as many spaces when PARMRK is set (depending on + * its flags, e.g. parity error). */ + left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1; + } else + left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + /* * If we are doing input canonicalization, and there are no * pending newlines, let characters through without limit, so -- cgit v0.10.2 From 6f9ea7ad7be10dca95e7ca57221c5f81be48d852 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:26 +0200 Subject: TTY: pty, stop passing NULL to free_tty_struct In case alloc_tty_struct fails in pty_common_install, we pass NULL to free_tty_struct. This is invalid as the function is not ready to cope with that. And even if it was, it is not nice to do that anyway. Signed-off-by: Jiri Slaby Reported-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 4399f1d..d9ea9e2 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -303,9 +303,11 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, int retval = -ENOMEM; o_tty = alloc_tty_struct(); + if (!o_tty) + goto err; ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); - if (!o_tty || !ports[0] || !ports[1]) + if (!ports[0] || !ports[1]) goto err_free_tty; if (!try_module_get(driver->other->owner)) { /* This cannot in fact currently happen */ @@ -360,6 +362,7 @@ err_free_tty: kfree(ports[0]); kfree(ports[1]); free_tty_struct(o_tty); +err: return retval; } -- cgit v0.10.2 From 3dd332c553996eec2593110b05abf8a4819b5c28 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:27 +0200 Subject: TTY: 68328serial, fix compilation tty_struct->termios is no longer a pointer. This was changed recently by "tty: move the termios object into the tty". But 68328serial was not changed, so we now have a compilation error: 68328serial.c: In function 'change_speed': 68328serial.c:518:22: error: invalid type argument of '->' (have 'struct ktermios') 68328serial.c: In function 'rs_set_ldisc': 68328serial.c:620:31: error: invalid type argument of '->' (have 'struct ktermios') 68328serial.c: In function 'rs_set_termios': 68328serial.c:988:20: error: invalid type argument of '->' (have 'struct ktermios') Fix that now. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 3ed20e4..cc4c092 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -515,7 +515,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty) unsigned cflag; int i; - cflag = tty->termios->c_cflag; + cflag = tty->termios.c_cflag; if (!(port = info->port)) return; @@ -617,7 +617,7 @@ static void rs_set_ldisc(struct tty_struct *tty) if (serial_paranoia_check(info, tty->name, "rs_set_ldisc")) return; - info->is_cons = (tty->termios->c_line == N_TTY); + info->is_cons = (tty->termios.c_line == N_TTY); printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off"); } @@ -985,7 +985,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) change_speed(info, tty); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios.c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_start(tty); } @@ -1070,7 +1070,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (tty->ldisc.close) (tty->ldisc.close)(tty); tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; + tty->termios.c_line = N_TTY; if (tty->ldisc.open) (tty->ldisc.open)(tty); } -- cgit v0.10.2 From 86176ed905454e568539c77e0cba5759085830bb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:28 +0200 Subject: TTY: n_gsm, use tty_port_install We need to link a port to a tty in install. And since dlci is allocated even in open, we need to create gsmtty_install, allocate dlci there and create also the link. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 7a4bf30..3778687 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2868,14 +2868,14 @@ static const struct tty_port_operations gsm_port_ops = { .dtr_rts = gsm_dtr_rts, }; - -static int gsmtty_open(struct tty_struct *tty, struct file *filp) +static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty) { struct gsm_mux *gsm; struct gsm_dlci *dlci; - struct tty_port *port; unsigned int line = tty->index; unsigned int mux = line >> 6; + bool alloc = false; + int ret; line = line & 0x3F; @@ -2890,13 +2890,30 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) if (gsm->dead) return -EL2HLT; dlci = gsm->dlci[line]; - if (dlci == NULL) + if (dlci == NULL) { + alloc = true; dlci = gsm_dlci_alloc(gsm, line); + } if (dlci == NULL) return -ENOMEM; - port = &dlci->port; - port->count++; + ret = tty_port_install(&dlci->port, driver, tty); + if (ret) { + if (alloc) + dlci_put(dlci); + return ret; + } + tty->driver_data = dlci; + + return 0; +} + +static int gsmtty_open(struct tty_struct *tty, struct file *filp) +{ + struct gsm_dlci *dlci = tty->driver_data; + struct tty_port *port = &dlci->port; + + port->count++; dlci_get(dlci); dlci_get(dlci->gsm->dlci[0]); mux_get(dlci->gsm); @@ -3085,6 +3102,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) /* Virtual ttys for the demux */ static const struct tty_operations gsmtty_ops = { + .install = gsmtty_install, .open = gsmtty_open, .close = gsmtty_close, .write = gsmtty_write, -- cgit v0.10.2 From d15684228a1f82555fcd3c5fcd86a0884bad29e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:29 +0200 Subject: misc: pti, add const to pci_device_id table It is annotated as __devinitconst. Despite the annotation is useless in most cases, const keyword is misssing there. So we are placing non-const data into rodata section. Fix that now. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index b7eb545..5cb61f7 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -76,7 +76,7 @@ struct pti_dev { */ static DEFINE_MUTEX(alloclock); -static struct pci_device_id pci_ids[] __devinitconst = { +static const struct pci_device_id pci_ids[] __devinitconst = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, {0} }; -- cgit v0.10.2 From c6333cc65d12fddf9cf79de3950b65bc142784e1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:30 +0200 Subject: misc: pti, pci drvdata cannot be NULL in ->remove As we set drvdata unconditionally in ->probe, we need not check if it is NULL. Let us remove the check. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 5cb61f7..88da085 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -400,16 +400,13 @@ EXPORT_SYMBOL_GPL(pti_writedata); */ static void __devexit pti_pci_remove(struct pci_dev *pdev) { - struct pti_dev *drv_data; + struct pti_dev *drv_data = pci_get_drvdata(pdev); - drv_data = pci_get_drvdata(pdev); - if (drv_data != NULL) { - pci_iounmap(pdev, drv_data->pti_ioaddr); - pci_set_drvdata(pdev, NULL); - kfree(drv_data); - pci_release_region(pdev, 1); - pci_disable_device(pdev); - } + pci_iounmap(pdev, drv_data->pti_ioaddr); + pci_set_drvdata(pdev, NULL); + kfree(drv_data); + pci_release_region(pdev, 1); + pci_disable_device(pdev); } /* -- cgit v0.10.2 From dda3f32c3a7201ee79e7e6a7b1d827b89759b4bc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:31 +0200 Subject: misc: pti, stop using iomap's unmap on ioremap space Ioremap space is different to iomap. ->probe function uses ioremap, but ->remove calls pci_iounmap. That one is illegal. Fix that by using iounmap. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 88da085..3bfc8e3 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -402,7 +402,7 @@ static void __devexit pti_pci_remove(struct pci_dev *pdev) { struct pti_dev *drv_data = pci_get_drvdata(pdev); - pci_iounmap(pdev, drv_data->pti_ioaddr); + iounmap(drv_data->pti_ioaddr); pci_set_drvdata(pdev, NULL); kfree(drv_data); pci_release_region(pdev, 1); -- cgit v0.10.2 From 065185f604c604ce77c43d7f26faf712f0bfa265 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:32 +0200 Subject: misc: pti, move ->remove to the PCI code The function is lost somewhere in the forest. Move it to have it along with probe and other pci_driver stuff. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 3bfc8e3..4a24421 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -393,22 +393,6 @@ void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count) } EXPORT_SYMBOL_GPL(pti_writedata); -/** - * pti_pci_remove()- Driver exit method to remove PTI from - * PCI bus. - * @pdev: variable containing pci info of PTI. - */ -static void __devexit pti_pci_remove(struct pci_dev *pdev) -{ - struct pti_dev *drv_data = pci_get_drvdata(pdev); - - iounmap(drv_data->pti_ioaddr); - pci_set_drvdata(pdev, NULL); - kfree(drv_data); - pci_release_region(pdev, 1); - pci_disable_device(pdev); -} - /* * for the tty_driver_*() basic function descriptions, see tty_driver.h. * Specific header comments made for PTI-related specifics. @@ -881,6 +865,22 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, return retval; } +/** + * pti_pci_remove()- Driver exit method to remove PTI from + * PCI bus. + * @pdev: variable containing pci info of PTI. + */ +static void __devexit pti_pci_remove(struct pci_dev *pdev) +{ + struct pti_dev *drv_data = pci_get_drvdata(pdev); + + iounmap(drv_data->pti_ioaddr); + pci_set_drvdata(pdev, NULL); + kfree(drv_data); + pci_release_region(pdev, 1); + pci_disable_device(pdev); +} + static struct pci_driver pti_pci_driver = { .name = PCINAME, .id_table = pci_ids, -- cgit v0.10.2 From 3140bae26c9105b4ec8ff4935631f2f09882553d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:33 +0200 Subject: misc: pti, do the opposite of ->probe in ->remove Currently, probe initializes some parts. Then, some of them are unwound in ->remove, some in module_exit. Let us do the opposite of whole ->probe in ->remove. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 4a24421..be6e679 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -874,11 +874,18 @@ static void __devexit pti_pci_remove(struct pci_dev *pdev) { struct pti_dev *drv_data = pci_get_drvdata(pdev); + unregister_console(&pti_console); + + tty_unregister_device(pti_tty_driver, 0); + tty_unregister_device(pti_tty_driver, 1); + iounmap(drv_data->pti_ioaddr); pci_set_drvdata(pdev, NULL); kfree(drv_data); pci_release_region(pdev, 1); pci_disable_device(pdev); + + misc_deregister(&pti_char_driver); } static struct pci_driver pti_pci_driver = { @@ -959,9 +966,6 @@ static void __exit pti_exit(void) { int retval; - tty_unregister_device(pti_tty_driver, 0); - tty_unregister_device(pti_tty_driver, 1); - retval = tty_unregister_driver(pti_tty_driver); if (retval) { pr_err("%s(%d): TTY unregistration failed of pti driver\n", @@ -971,17 +975,6 @@ static void __exit pti_exit(void) } pci_unregister_driver(&pti_pci_driver); - - retval = misc_deregister(&pti_char_driver); - if (retval) { - pr_err("%s(%d): CHAR unregistration failed of pti driver\n", - __func__, __LINE__); - pr_err("%s(%d): Error value returned: %d\n", - __func__, __LINE__, retval); - } - - unregister_console(&pti_console); - return; } module_init(pti_init); -- cgit v0.10.2 From fbf1c247dac8574ef3973adce4b20d40ff22214e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:34 +0200 Subject: misc: pti, fix fail paths Fail paths in ->probe and pti_init are incomplete. Fix that by adding proper clean-up paths. Note that we used to leak tty_driver on module unload. This is fixed here too. tty_unregister_driver needs not retval checking, so remove that. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index be6e679..90de855 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -811,7 +811,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, __func__, __LINE__); pr_err("%s(%d): Error value returned: %d\n", __func__, __LINE__, retval); - return retval; + goto err; } retval = pci_enable_device(pdev); @@ -819,17 +819,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "%s: pci_enable_device() returned error %d\n", __func__, retval); - return retval; + goto err_unreg_misc; } drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); - if (drv_data == NULL) { retval = -ENOMEM; dev_err(&pdev->dev, "%s(%d): kmalloc() returned NULL memory.\n", __func__, __LINE__); - return retval; + goto err_disable_pci; } drv_data->pti_addr = pci_resource_start(pdev, pci_bar); @@ -838,18 +837,15 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "%s(%d): pci_request_region() returned error %d\n", __func__, __LINE__, retval); - kfree(drv_data); - return retval; + goto err_free_dd; } drv_data->aperture_base = drv_data->pti_addr+APERTURE_14; drv_data->pti_ioaddr = ioremap_nocache((u32)drv_data->aperture_base, APERTURE_LEN); if (!drv_data->pti_ioaddr) { - pci_release_region(pdev, pci_bar); retval = -ENOMEM; - kfree(drv_data); - return retval; + goto err_rel_reg; } pci_set_drvdata(pdev, drv_data); @@ -862,6 +858,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, register_console(&pti_console); + return 0; +err_rel_reg: + pci_release_region(pdev, pci_bar); +err_free_dd: + kfree(drv_data); +err_disable_pci: + pci_disable_device(pdev); +err_unreg_misc: + misc_deregister(&pti_char_driver); +err: return retval; } @@ -937,25 +943,24 @@ static int __init pti_init(void) pr_err("%s(%d): Error value returned: %d\n", __func__, __LINE__, retval); - pti_tty_driver = NULL; - return retval; + goto put_tty; } retval = pci_register_driver(&pti_pci_driver); - if (retval) { pr_err("%s(%d): PCI registration failed of pti driver\n", __func__, __LINE__); pr_err("%s(%d): Error value returned: %d\n", __func__, __LINE__, retval); - - tty_unregister_driver(pti_tty_driver); - pr_err("%s(%d): Unregistering TTY part of pti driver\n", - __func__, __LINE__); - pti_tty_driver = NULL; - return retval; + goto unreg_tty; } + return 0; +unreg_tty: + tty_unregister_driver(pti_tty_driver); +put_tty: + put_tty_driver(pti_tty_driver); + pti_tty_driver = NULL; return retval; } @@ -964,17 +969,9 @@ static int __init pti_init(void) */ static void __exit pti_exit(void) { - int retval; - - retval = tty_unregister_driver(pti_tty_driver); - if (retval) { - pr_err("%s(%d): TTY unregistration failed of pti driver\n", - __func__, __LINE__); - pr_err("%s(%d): Error value returned: %d\n", - __func__, __LINE__, retval); - } - + tty_unregister_driver(pti_tty_driver); pci_unregister_driver(&pti_pci_driver); + put_tty_driver(pti_tty_driver); } module_init(pti_init); -- cgit v0.10.2 From 5bd420009716f3348610fdf9c6307f0db583ba04 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:35 +0200 Subject: misc: pti, fix tty_port count We now have *one* tty_port for both TTYs. How this was supposed to work? Change it to have a tty_port for each of TTYs. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 90de855..fe76f9d 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -60,7 +60,7 @@ struct pti_tty { }; struct pti_dev { - struct tty_port port; + struct tty_port port[PTITTY_MINOR_NUM]; unsigned long pti_addr; unsigned long aperture_base; void __iomem *pti_ioaddr; @@ -427,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp) * also removes a locking requirement for the actual write * procedure. */ - return tty_port_open(&drv_data->port, tty, filp); + return tty_port_open(&drv_data->port[tty->index], tty, filp); } /** @@ -443,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp) */ static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp) { - tty_port_close(&drv_data->port, tty, filp); + tty_port_close(&drv_data->port[tty->index], tty, filp); } /** @@ -799,6 +799,7 @@ static const struct tty_port_operations tty_port_ops = { static int __devinit pti_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + unsigned int a; int retval = -EINVAL; int pci_bar = 1; @@ -850,11 +851,13 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, drv_data); - tty_port_init(&drv_data->port); - drv_data->port.ops = &tty_port_ops; + for (a = 0; a < PTITTY_MINOR_NUM; a++) { + struct tty_port *port = &drv_data->port[a]; + tty_port_init(port); + port->ops = &tty_port_ops; - tty_register_device(pti_tty_driver, 0, &pdev->dev); - tty_register_device(pti_tty_driver, 1, &pdev->dev); + tty_register_device(pti_tty_driver, a, &pdev->dev); + } register_console(&pti_console); -- cgit v0.10.2 From c565ee07708e19474cd1133bf50289a36b5bcc26 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:36 +0200 Subject: misc: pti, use tty_port_register_device So now we have enough of tty_ports, so we can signal the TTY layer to use them by tty_port_register_device. The upside is that we look like we can introduce tty_port_easy_open and put it directly as tty_operations->open to drivers doing nothing in open and using tty_port_register_device. Because the easy open can obtain a tty_port rather easily from a tty now. Heh, what a nice by-product. Signed-off-by: Jiri Slaby Cc: J Freyensee Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index fe76f9d..4999b34 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -427,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp) * also removes a locking requirement for the actual write * procedure. */ - return tty_port_open(&drv_data->port[tty->index], tty, filp); + return tty_port_open(tty->port, tty, filp); } /** @@ -443,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp) */ static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp) { - tty_port_close(&drv_data->port[tty->index], tty, filp); + tty_port_close(tty->port, tty, filp); } /** @@ -856,7 +856,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev, tty_port_init(port); port->ops = &tty_port_ops; - tty_register_device(pti_tty_driver, a, &pdev->dev); + tty_port_register_device(port, pti_tty_driver, a, &pdev->dev); } register_console(&pti_console); -- cgit v0.10.2 From 38daf88ae16d053cffc8745e05b9f7a324ce36eb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:37 +0200 Subject: mxser: allow overlapping vector For many cards, this saves some IO space because interrupt status port has precedence over the rest of ports on the card. Hence it can be mapped to a hole in I/O ports. Here we add a kernel parameter which allows that if a user wants to. But they need to explicitly enable it by a module parameter. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index c162ee9..e64fe40 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = { * The MOXA Smartio/Industio serial driver boot-time initialization code! */ +static bool allow_overlapping_vector; +module_param(allow_overlapping_vector, bool, 444); +MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)"); + +static bool mxser_overlapping_vector(struct mxser_board *brd) +{ + return allow_overlapping_vector && + brd->vector >= brd->ports[0].ioaddr && + brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports; +} + +static int mxser_request_vector(struct mxser_board *brd) +{ + if (mxser_overlapping_vector(brd)) + return 0; + return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO; +} + +static void mxser_release_vector(struct mxser_board *brd) +{ + if (mxser_overlapping_vector(brd)) + return; + release_region(brd->vector, 1); +} + static void mxser_release_ISA_res(struct mxser_board *brd) { free_irq(brd->irq, brd); release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); - release_region(brd->vector, 1); + mxser_release_vector(brd); } static int __devinit mxser_initbrd(struct mxser_board *brd, @@ -2396,7 +2421,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) { - int id, i, bits; + int id, i, bits, ret; unsigned short regs[16], irq; unsigned char scratch, scratch2; @@ -2492,13 +2517,15 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) 8 * brd->info->nports - 1); return -EIO; } - if (!request_region(brd->vector, 1, "mxser(vector)")) { + + ret = mxser_request_vector(brd); + if (ret) { release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); printk(KERN_ERR "mxser: can't request interrupt vector region: " "0x%.8lx-0x%.8lx\n", brd->ports[0].ioaddr, brd->ports[0].ioaddr + 8 * brd->info->nports - 1); - return -EIO; + return ret; } return brd->info->nports; -- cgit v0.10.2 From f06fb543c1d0cbd721250b72ee1244178a38aa9d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:38 +0200 Subject: TTY: ttyprintk, unregister tty driver on failure When the tty_printk driver fails to create a node in sysfs, the system crashes. It is because the driver registers a tty driver and frees it without deregistering it first. The fix is easy: add a call to tty_unregister_driver to the fail path. This is very unlikely to happen in usual environment => no need for stable. The crash occurs at some place where we iterate over tty drivers first. It may look like this: BUG: unable to handle kernel paging request at ffffffffffffff84 IP: [] tty_open+0xd6/0x650 PGD 1a0d067 PUD 1a0e067 PMD 0 Oops: 0000 [#1] PREEMPT SMP Modules linked in: CPU 0 Pid: 1183, comm: boot.localnet Tainted: G W 3.5.0-rc7-next-20120716+ #369 Bochs Bochs RIP: 0010:[] [] tty_open+0xd6/0x650 RSP: 0018:ffff8800162b3b98 EFLAGS: 00010207 RAX: 0000000000000000 RBX: ffff880016ba6200 RCX: 0000000000002208 RDX: 0000000000000000 RSI: 00000000000000d0 RDI: ffffffff81a35080 RBP: ffff8800162b3c08 R08: ffffffff81276f42 R09: 0000000000400040 R10: ffff8800161dc005 R11: ffff8800188ee048 R12: 0000000000000000 R13: ffffffffffffff58 R14: 0000000000400040 R15: 0000000000008000 FS: 00007f3684abd700(0000) GS:ffff880018e00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffffffff84 CR3: 000000001503e000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process boot.localnet (pid: 1183, threadinfo ffff8800162b2000, task ffff8800188c5880) Stack: ffff8800162b3c08 ffffffff81363d63 ffffffff81a62940 ffff8800189b4e88 ffff8800188c5880 ffffffff81123180 0000000000000000 ffffffff18b20600 0000000000000000 ffff8800189b4e88 ffff880016ba6200 ffff880018b20600 Call Trace: [] ? kobj_lookup+0x103/0x160 [] ? mount_fs+0x110/0x110 [] chrdev_open+0x9c/0x1a0 [] ? cdev_put+0x30/0x30 [] do_dentry_open.isra.19+0x1e6/0x270 [] finish_open+0x65/0xa0 [] do_last.isra.52+0x26e/0xd80 [] ? inode_permission+0x13/0x50 [] ? link_path_walk+0x63/0x940 [] path_openat+0xab/0x3d0 [] do_filp_open+0x3d/0xa0 [] ? alloc_fd+0xd2/0x120 [] do_sys_open+0xf3/0x1d0 [] sys_open+0x1c/0x20 [] system_call_fastpath+0x16/0x1b Signed-off-by: Jiri Slaby Cc: Samo Pogacnik Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 46b77ed..9b1e5e0 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -217,6 +217,7 @@ static int __init ttyprintk_init(void) return 0; error: + tty_unregister_driver(ttyprintk_driver); put_tty_driver(ttyprintk_driver); ttyprintk_driver = NULL; return ret; -- cgit v0.10.2 From ee8b593affdf893012e57f4c54a21984d1b0d92e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:39 +0200 Subject: TTY: ttyprintk, don't touch behind tty->write_buf If a user provides a buffer larger than a tty->write_buf chunk and passes '\r' at the end of the buffer, we touch an out-of-bound memory. Add a check there to prevent this. Signed-off-by: Jiri Slaby Cc: stable@vger.kernel.org (everything maintained past v2.6.37) Cc: Samo Pogacnik Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 9b1e5e0..08755c5 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count) tmp[tpk_curr + 1] = '\0'; printk(KERN_INFO "%s%s", tpk_tag, tmp); tpk_curr = 0; - if (buf[i + 1] == '\n') + if ((i + 1) < count && buf[i + 1] == '\n') i++; break; case '\n': -- cgit v0.10.2 From 536a3440a27f8687090bdf33468b003bc0f810cf Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:40 +0200 Subject: TTY: ttyprintk, initialize tty_port earlier After tty_register_driver is called, it is too late to initialize a guy with which we operate in open. When a process already called open(2) on that node, the structures may be in use uninitialized. Move the initialization prior to tty_register_driver. Signed-off-by: Jiri Slaby Cc: Samo Pogacnik Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 08755c5..be1c3fb 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -180,6 +180,10 @@ static int __init ttyprintk_init(void) int ret = -ENOMEM; void *rp; + tty_port_init(&tpk_port.port); + tpk_port.port.ops = &null_ops; + mutex_init(&tpk_port.port_write_mutex); + ttyprintk_driver = alloc_tty_driver(1); if (!ttyprintk_driver) return ret; @@ -210,10 +214,6 @@ static int __init ttyprintk_init(void) goto error; } - tty_port_init(&tpk_port.port); - tpk_port.port.ops = &null_ops; - mutex_init(&tpk_port.port_write_mutex); - return 0; error: -- cgit v0.10.2 From 2312e4f3b2f17cac2cf257c759ad48eb80fdf230 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:41 +0200 Subject: TTY: tty3270, free tty driver properly On module unload, in tty3270_exit, we forgot to free the tty driver. Add there a call to put_tty_driver. Signed-off-by: Jiri Slaby Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 1928f34..215037c 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1800,6 +1800,7 @@ tty3270_exit(void) driver = tty3270_driver; tty3270_driver = NULL; tty_unregister_driver(driver); + put_tty_driver(driver); tty3270_del_views(); } -- cgit v0.10.2 From 7f0bc6a68ed93f3b4ad77b94df5ef32446c583e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:42 +0200 Subject: TTY: pass flags to alloc_tty_driver We need to allow drivers that use neither tty_port_install nor tty_port_register_device to link a tty_port to a tty somehow. To avoid a race with open, this has to be performed before tty_register_device. But currently tty_driver->ports is allocated even in tty_register_device because we do not know whether this is the PTY driver. The PTY driver is special here due to an excessive count of lines it declares to handle. We cannot handle tty_ports there this way. To circumvent this, we start passing tty_driver flags to alloc_tty_driver already and we create tty_alloc_driver for this purpose. There we can allocate tty_driver->ports and do all the magic between tty_alloc_driver and tty_register_device. Later we will introduce tty_port_link_device function for that purpose. All drivers should eventually switch to this new tty driver allocation interface. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 6902244..098a7c7 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3061,21 +3061,37 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) } EXPORT_SYMBOL(tty_unregister_device); -struct tty_driver *__alloc_tty_driver(int lines, struct module *owner) +/** + * __tty_alloc_driver -- allocate tty driver + * @lines: count of lines this driver can handle at most + * @owner: module which is repsonsible for this driver + * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags + * + * This should not be called directly, some of the provided macros should be + * used instead. Use IS_ERR and friends on @retval. + */ +struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, + unsigned long flags) { struct tty_driver *driver; + if (!lines) + return ERR_PTR(-EINVAL); + driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); - if (driver) { - kref_init(&driver->kref); - driver->magic = TTY_DRIVER_MAGIC; - driver->num = lines; - driver->owner = owner; - /* later we'll move allocation of tables here */ - } + if (!driver) + return ERR_PTR(-ENOMEM); + + kref_init(&driver->kref); + driver->magic = TTY_DRIVER_MAGIC; + driver->num = lines; + driver->owner = owner; + driver->flags = flags; + /* later we'll move allocation of tables here */ + return driver; } -EXPORT_SYMBOL(__alloc_tty_driver); +EXPORT_SYMBOL(__tty_alloc_driver); static void destruct_tty_driver(struct kref *kref) { diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 80e72dc..3adc362 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -296,11 +296,11 @@ struct tty_driver { int name_base; /* offset of printed name */ int major; /* major device number */ int minor_start; /* start of minor device number */ - int num; /* number of devices allocated */ + unsigned int num; /* number of devices allocated */ short type; /* type of tty driver */ short subtype; /* subtype of tty driver */ struct ktermios init_termios; /* Initial termios */ - int flags; /* tty driver flags */ + unsigned long flags; /* tty driver flags */ struct proc_dir_entry *proc_entry; /* /proc fs entry */ struct tty_driver *other; /* only used for the PTY driver */ @@ -322,7 +322,8 @@ struct tty_driver { extern struct list_head tty_drivers; -extern struct tty_driver *__alloc_tty_driver(int lines, struct module *owner); +extern struct tty_driver *__tty_alloc_driver(unsigned int lines, + struct module *owner, unsigned long flags); extern void put_tty_driver(struct tty_driver *driver); extern void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op); @@ -330,7 +331,21 @@ extern struct tty_driver *tty_find_polling_driver(char *name, int *line); extern void tty_driver_kref_put(struct tty_driver *driver); -#define alloc_tty_driver(lines) __alloc_tty_driver(lines, THIS_MODULE) +/* Use TTY_DRIVER_* flags below */ +#define tty_alloc_driver(lines, flags) \ + __tty_alloc_driver(lines, THIS_MODULE, flags) + +/* + * DEPRECATED Do not use this in new code, use tty_alloc_driver instead. + * (And change the return value checks.) + */ +static inline struct tty_driver *alloc_tty_driver(unsigned int lines) +{ + struct tty_driver *ret = tty_alloc_driver(lines, 0); + if (IS_ERR(ret)) + return NULL; + return ret; +} static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) { -- cgit v0.10.2 From 21aca2fa00259f781d228496631b61dbb4274e90 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 8 Aug 2012 22:26:41 +0200 Subject: TTY: pty, switch to tty_alloc_driver Switch to the new driver allocation interface, as this is one of the special call-sites. Here, we need TTY_DRIVER_DYNAMIC_ALLOC to not allocate tty_driver->ports, cdevs and potentially other structures because we reserve too many lines in pty. Instead, it provides the tty_port<->tty_struct link in tty->ops->install already. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index d9ea9e2..f5a27c6 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -444,11 +444,17 @@ static void __init legacy_pty_init(void) if (legacy_count <= 0) return; - pty_driver = alloc_tty_driver(legacy_count); + pty_driver = tty_alloc_driver(legacy_count, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_ALLOC); if (!pty_driver) panic("Couldn't allocate pty driver"); - pty_slave_driver = alloc_tty_driver(legacy_count); + pty_slave_driver = tty_alloc_driver(legacy_count, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_ALLOC); if (!pty_slave_driver) panic("Couldn't allocate pty slave driver"); @@ -465,7 +471,6 @@ static void __init legacy_pty_init(void) pty_driver->init_termios.c_lflag = 0; pty_driver->init_termios.c_ispeed = 38400; pty_driver->init_termios.c_ospeed = 38400; - pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; pty_driver->other = pty_slave_driver; tty_set_operations(pty_driver, &master_pty_ops_bsd); @@ -479,8 +484,6 @@ static void __init legacy_pty_init(void) pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pty_slave_driver->init_termios.c_ispeed = 38400; pty_slave_driver->init_termios.c_ospeed = 38400; - pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW; pty_slave_driver->other = pty_driver; tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd); @@ -673,10 +676,20 @@ static struct file_operations ptmx_fops; static void __init unix98_pty_init(void) { - ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); + ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_DEVPTS_MEM | + TTY_DRIVER_DYNAMIC_ALLOC); if (!ptm_driver) panic("Couldn't allocate Unix98 ptm driver"); - pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); + pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_DEVPTS_MEM | + TTY_DRIVER_DYNAMIC_ALLOC); if (!pts_driver) panic("Couldn't allocate Unix98 pts driver"); @@ -693,8 +706,6 @@ static void __init unix98_pty_init(void) ptm_driver->init_termios.c_lflag = 0; ptm_driver->init_termios.c_ispeed = 38400; ptm_driver->init_termios.c_ospeed = 38400; - ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &ptm_unix98_ops); @@ -708,8 +719,6 @@ static void __init unix98_pty_init(void) pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; pts_driver->init_termios.c_ispeed = 38400; pts_driver->init_termios.c_ospeed = 38400; - pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; tty_set_operations(pts_driver, &pty_unix98_ops); diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 3adc362..1a85f00 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -391,6 +391,9 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) * the requested timeout to the caller instead of using a simple * on/off interface. * + * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are + * needed per line for this driver as it would waste memory. + * The driver will take care. */ #define TTY_DRIVER_INSTALLED 0x0001 #define TTY_DRIVER_RESET_TERMIOS 0x0002 @@ -398,6 +401,7 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) #define TTY_DRIVER_DYNAMIC_DEV 0x0008 #define TTY_DRIVER_DEVPTS_MEM 0x0010 #define TTY_DRIVER_HARDWARE_BREAK 0x0020 +#define TTY_DRIVER_DYNAMIC_ALLOC 0x0040 /* tty driver types */ #define TTY_DRIVER_TYPE_SYSTEM 0x0001 -- cgit v0.10.2 From 16a02081baa15becdb7d6460659e7832e6524d93 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 8 Aug 2012 22:26:42 +0200 Subject: TTY: move allocations to tty_alloc_driver So now, that we have flags and know everything needed, keep a promise and move all the tables and ports allocation from tty_register_driver to tty_alloc_driver. Not only that it makes sense, but we need this for tty_port_link_device which needs tty_driver->ports but is to be called before tty_register_driver. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 098a7c7..a67609b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3074,6 +3074,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, unsigned long flags) { struct tty_driver *driver; + int err; if (!lines) return ERR_PTR(-EINVAL); @@ -3087,9 +3088,34 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, driver->num = lines; driver->owner = owner; driver->flags = flags; - /* later we'll move allocation of tables here */ + + if (!(flags & TTY_DRIVER_DEVPTS_MEM)) { + driver->ttys = kcalloc(lines, sizeof(*driver->ttys), + GFP_KERNEL); + driver->termios = kcalloc(lines, sizeof(*driver->termios), + GFP_KERNEL); + if (!driver->ttys || !driver->termios) { + err = -ENOMEM; + goto err_free_all; + } + } + + if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) { + driver->ports = kcalloc(lines, sizeof(*driver->ports), + GFP_KERNEL); + if (!driver->ports) { + err = -ENOMEM; + goto err_free_all; + } + } return driver; +err_free_all: + kfree(driver->ports); + kfree(driver->ttys); + kfree(driver->termios); + kfree(driver); + return ERR_PTR(err); } EXPORT_SYMBOL(__tty_alloc_driver); @@ -3098,7 +3124,6 @@ static void destruct_tty_driver(struct kref *kref) struct tty_driver *driver = container_of(kref, struct tty_driver, kref); int i; struct ktermios *tp; - void *p; if (driver->flags & TTY_DRIVER_INSTALLED) { /* @@ -3115,14 +3140,12 @@ static void destruct_tty_driver(struct kref *kref) if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) tty_unregister_device(driver, i); } - p = driver->ttys; proc_tty_unregister_driver(driver); - driver->ttys = NULL; - driver->termios = NULL; - kfree(p); cdev_del(&driver->cdev); } kfree(driver->ports); + kfree(driver->termios); + kfree(driver->ttys); kfree(driver); } @@ -3153,27 +3176,8 @@ int tty_register_driver(struct tty_driver *driver) int error; int i; dev_t dev; - void **p = NULL; struct device *d; - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { - p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL); - if (!p) - return -ENOMEM; - } - /* - * There is too many lines in PTY and we won't need the array there - * since it has an ->install hook where it assigns ports properly. - */ - if (driver->type != TTY_DRIVER_TYPE_PTY) { - driver->ports = kcalloc(driver->num, sizeof(struct tty_port *), - GFP_KERNEL); - if (!driver->ports) { - error = -ENOMEM; - goto err_free_p; - } - } - if (!driver->major) { error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, driver->name); @@ -3186,15 +3190,7 @@ int tty_register_driver(struct tty_driver *driver) error = register_chrdev_region(dev, driver->num, driver->name); } if (error < 0) - goto err_free_p; - - if (p) { - driver->ttys = (struct tty_struct **)p; - driver->termios = (struct ktermios **)(p + driver->num); - } else { - driver->ttys = NULL; - driver->termios = NULL; - } + goto err; cdev_init(&driver->cdev, &tty_fops); driver->cdev.owner = driver->owner; @@ -3211,7 +3207,7 @@ int tty_register_driver(struct tty_driver *driver) d = tty_register_device(driver, i, NULL); if (IS_ERR(d)) { error = PTR_ERR(d); - goto err; + goto err_unreg_devs; } } } @@ -3219,7 +3215,7 @@ int tty_register_driver(struct tty_driver *driver) driver->flags |= TTY_DRIVER_INSTALLED; return 0; -err: +err_unreg_devs: for (i--; i >= 0; i--) tty_unregister_device(driver, i); @@ -3229,10 +3225,7 @@ err: err_unreg_char: unregister_chrdev_region(dev, driver->num); - driver->ttys = NULL; - driver->termios = NULL; -err_free_p: /* destruct_tty_driver will free driver->ports */ - kfree(p); +err: return error; } EXPORT_SYMBOL(tty_register_driver); -- cgit v0.10.2 From 0019b4089ccef8148d8be83cc8adfc81a75b47d4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 8 Aug 2012 22:26:43 +0200 Subject: TTY: add support for unnumbered device nodes This allows drivers like ttyprintk to avoid hacks to create an unnumbered node in /dev. It used to set TTY_DRIVER_DYNAMIC_DEV in flags and call device_create on its own. That is incorrect, because TTY_DRIVER_DYNAMIC_DEV may be set only if tty_register_device is called explicitly. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index be1c3fb..9e6272f 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -178,13 +178,15 @@ static struct tty_driver *ttyprintk_driver; static int __init ttyprintk_init(void) { int ret = -ENOMEM; - void *rp; tty_port_init(&tpk_port.port); tpk_port.port.ops = &null_ops; mutex_init(&tpk_port.port_write_mutex); - ttyprintk_driver = alloc_tty_driver(1); + ttyprintk_driver = tty_alloc_driver(1, + TTY_DRIVER_RESET_TERMIOS | + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_UNNUMBERED_NODE); if (!ttyprintk_driver) return ret; @@ -195,8 +197,6 @@ static int __init ttyprintk_init(void) ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE; ttyprintk_driver->init_termios = tty_std_termios; ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; - ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(ttyprintk_driver, &ttyprintk_ops); ret = tty_register_driver(ttyprintk_driver); @@ -205,15 +205,6 @@ static int __init ttyprintk_init(void) goto error; } - /* create our unnumbered device */ - rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL, - ttyprintk_driver->name); - if (IS_ERR(rp)) { - printk(KERN_ERR "Couldn't create ttyprintk device\n"); - ret = PTR_ERR(rp); - goto error; - } - return 0; error: diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index a67609b..4d9898c 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1216,7 +1216,10 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) */ static void tty_line_name(struct tty_driver *driver, int index, char *p) { - sprintf(p, "%s%d", driver->name, index + driver->name_base); + if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE) + strcpy(p, driver->name); + else + sprintf(p, "%s%d", driver->name, index + driver->name_base); } /** @@ -3076,7 +3079,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, struct tty_driver *driver; int err; - if (!lines) + if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1)) return ERR_PTR(-EINVAL); driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 1a85f00..44e05b7 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -394,6 +394,11 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are * needed per line for this driver as it would waste memory. * The driver will take care. + * + * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In + * other words create /dev/ttyprintk and not /dev/ttyprintk0. + * Applicable only when a driver for a single tty device is + * being allocated. */ #define TTY_DRIVER_INSTALLED 0x0001 #define TTY_DRIVER_RESET_TERMIOS 0x0002 @@ -402,6 +407,7 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) #define TTY_DRIVER_DEVPTS_MEM 0x0010 #define TTY_DRIVER_HARDWARE_BREAK 0x0020 #define TTY_DRIVER_DYNAMIC_ALLOC 0x0040 +#define TTY_DRIVER_UNNUMBERED_NODE 0x0080 /* tty driver types */ #define TTY_DRIVER_TYPE_SYSTEM 0x0001 -- cgit v0.10.2 From 7e73eca6a7b2967423902a4543821bb97cbbe698 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 8 Aug 2012 22:26:44 +0200 Subject: TTY: move cdev_add to tty_register_device We need the /dev/ node not to be available before we call tty_register_device. Otherwise we might race with open and tty_struct->port might not be available at that time. This is not an issue now, but would be a problem after "TTY: use tty_port_register_device" is applied. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 4d9898c..28c3e86 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3006,6 +3006,15 @@ EXPORT_SYMBOL_GPL(tty_put_char); struct class *tty_class; +static int tty_cdev_add(struct tty_driver *driver, dev_t dev, + unsigned int index, unsigned int count) +{ + /* init here, since reused cdevs cause crashes */ + cdev_init(&driver->cdevs[index], &tty_fops); + driver->cdevs[index].owner = driver->owner; + return cdev_add(&driver->cdevs[index], dev, count); +} + /** * tty_register_device - register a tty device * @driver: the tty driver that describes the tty device @@ -3028,8 +3037,10 @@ struct class *tty_class; struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { + struct device *ret; char name[64]; dev_t dev = MKDEV(driver->major, driver->minor_start) + index; + bool cdev = false; if (index >= driver->num) { printk(KERN_ERR "Attempt to register invalid tty line number " @@ -3042,7 +3053,18 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, else tty_line_name(driver, index, name); - return device_create(tty_class, device, dev, NULL, name); + if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { + int error = tty_cdev_add(driver, dev, index, 1); + if (error) + return ERR_PTR(error); + cdev = true; + } + + ret = device_create(tty_class, device, dev, NULL, name); + if (IS_ERR(ret) && cdev) + cdev_del(&driver->cdevs[index]); + + return ret; } EXPORT_SYMBOL(tty_register_device); @@ -3061,6 +3083,8 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) { device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); + if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) + cdev_del(&driver->cdevs[index]); } EXPORT_SYMBOL(tty_unregister_device); @@ -3077,6 +3101,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, unsigned long flags) { struct tty_driver *driver; + unsigned int cdevs = 1; int err; if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1)) @@ -3110,6 +3135,13 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, err = -ENOMEM; goto err_free_all; } + cdevs = lines; + } + + driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL); + if (!driver->cdevs) { + err = -ENOMEM; + goto err_free_all; } return driver; @@ -3144,8 +3176,10 @@ static void destruct_tty_driver(struct kref *kref) tty_unregister_device(driver, i); } proc_tty_unregister_driver(driver); - cdev_del(&driver->cdev); + if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) + cdev_del(&driver->cdevs[0]); } + kfree(driver->cdevs); kfree(driver->ports); kfree(driver->termios); kfree(driver->ttys); @@ -3195,11 +3229,11 @@ int tty_register_driver(struct tty_driver *driver) if (error < 0) goto err; - cdev_init(&driver->cdev, &tty_fops); - driver->cdev.owner = driver->owner; - error = cdev_add(&driver->cdev, dev, driver->num); - if (error) - goto err_unreg_char; + if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) { + error = tty_cdev_add(driver, dev, 0, driver->num); + if (error) + goto err_unreg_char; + } mutex_lock(&tty_mutex); list_add(&driver->tty_drivers, &tty_drivers); diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 44e05b7..dd976cf 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -289,7 +289,7 @@ struct tty_operations { struct tty_driver { int magic; /* magic number for this structure */ struct kref kref; /* Reference management */ - struct cdev cdev; + struct cdev *cdevs; struct module *owner; const char *driver_name; const char *name; -- cgit v0.10.2 From 734cc1783816ae358cef45673a29bf7af974e147 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:47 +0200 Subject: TTY: use tty_port_register_device Currently we have no way to assign tty->port while performing tty installation. There are two ways to provide the link tty_struct => tty_port. Either by calling tty_port_install from tty->ops->install or tty_port_register_device called instead of tty_register_device when the device is being set up after connected. In this patch we modify most of the drivers to do the latter. When the drivers use tty_register_device and we have tty_port already, we switch to tty_port_register_device. So we have the tty_struct => tty_port link for free for those. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index bbaf2c5..457475f 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -409,7 +409,8 @@ int setup_one_line(struct line *lines, int n, char *init, line->valid = 1; err = parse_chan_pair(new, line, n, opts, error_out); if (!err) { - struct device *d = tty_register_device(driver, n, NULL); + struct device *d = tty_port_register_device(&line->port, + driver, n, NULL); if (IS_ERR(d)) { *error_out = "Failed to register device"; err = PTR_ERR(d); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 38c4bd8..c679867 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci) mp->minor = minor; - dev = tty_register_device(capinc_tty_driver, minor, NULL); + dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor, + NULL); if (IS_ERR(dev)) goto err_out2; diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index f9aab74..67abf3f 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs) tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs); mutex_lock(&cs->mutex); - cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL); + cs->tty_dev = tty_port_register_device(&cs->port, drv->tty, + cs->minor_index, NULL); if (!IS_ERR(cs->tty_dev)) dev_set_drvdata(cs->tty_dev, cs); diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index 372c032..d2339ea 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -1132,8 +1132,8 @@ static int sdio_uart_probe(struct sdio_func *func, kfree(port); } else { struct device *dev; - dev = tty_register_device(sdio_uart_tty_driver, - port->index, &func->dev); + dev = tty_port_register_device(&port->port, + sdio_uart_tty_driver, port->index, &func->dev); if (IS_ERR(dev)) { sdio_uart_port_remove(port); ret = PTR_ERR(dev); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 7736af7..605a4ba 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2287,9 +2287,11 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, if (minor < 0) goto exit; + tty_port_init(&serial->port); + /* register our minor number */ - serial->parent->dev = tty_register_device(tty_drv, minor, - &serial->parent->interface->dev); + serial->parent->dev = tty_port_register_device(&serial->port, tty_drv, + minor, &serial->parent->interface->dev); dev = serial->parent->dev; dev_set_drvdata(dev, serial->parent); i = device_create_file(dev, &dev_attr_hsotype); @@ -2298,7 +2300,6 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, serial->minor = minor; serial->magic = HSO_SERIAL_MAGIC; spin_lock_init(&serial->serial_lock); - tty_port_init(&serial->port); serial->num_rx_urbs = num_urbs; /* RX, allocate urb and initialize */ diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c index 394f5de..a68d981 100644 --- a/drivers/staging/ipack/devices/ipoctal.c +++ b/drivers/staging/ipack/devices/ipoctal.c @@ -502,7 +502,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, ipoctal->pointer_read[i] = 0; ipoctal->pointer_write[i] = 0; ipoctal->nb_bytes[i] = 0; - tty_register_device(tty, i, NULL); + tty_port_register_device(&ipoctal->tty_port[i], tty, i, NULL); /* * Enable again the RX. TX will be enabled when diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index c8850ea..e3954da 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -3289,7 +3289,7 @@ static int __init cy_detect_isa(void) struct cyclades_card *card; unsigned short cy_isa_irq, nboard; void __iomem *cy_isa_address; - unsigned short i, j, cy_isa_nchan; + unsigned short i, j, k, cy_isa_nchan; int isparam = 0; nboard = 0; @@ -3392,9 +3392,10 @@ static int __init cy_detect_isa(void) (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)), cy_isa_irq, cy_isa_nchan, cy_next_channel); - for (j = cy_next_channel; - j < cy_next_channel + cy_isa_nchan; j++) - tty_register_device(cy_serial_driver, j, NULL); + for (k = 0, j = cy_next_channel; + j < cy_next_channel + cy_isa_nchan; j++, k++) + tty_port_register_device(&card->ports[k].port, + cy_serial_driver, j, NULL); cy_next_channel += cy_isa_nchan; } return nboard; @@ -3698,7 +3699,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, void __iomem *addr0 = NULL, *addr2 = NULL; char *card_name = NULL; u32 uninitialized_var(mailbox); - unsigned int device_id, nchan = 0, card_no, i; + unsigned int device_id, nchan = 0, card_no, i, j; unsigned char plx_ver; int retval, irq; @@ -3909,8 +3910,9 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); - for (i = cy_next_channel; i < cy_next_channel + nchan; i++) - tty_register_device(cy_serial_driver, i, &pdev->dev); + for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++) + tty_port_register_device(&card->ports[j].port, + cy_serial_driver, i, &pdev->dev); cy_next_channel += nchan; return 0; diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 4813684..4ab936b 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -738,16 +738,17 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev) goto error; } - bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev); + tty_port_init(&bc->port); + bc->port.ops = &ehv_bc_tty_port_ops; + + bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i, + &pdev->dev); if (IS_ERR(bc->dev)) { ret = PTR_ERR(bc->dev); dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret); goto error; } - tty_port_init(&bc->port); - bc->port.ops = &ehv_bc_tty_port_ops; - dev_set_drvdata(&pdev->dev, bc); dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n", diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index f8b5fa0..160f0ad 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -476,7 +476,7 @@ static int add_tty(int j, mutex_init(&ttys[j]->ipw_tty_mutex); tty_port_init(&ttys[j]->port); - tty_register_device(ipw_tty_driver, j, NULL); + tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL); ipwireless_associate_network_tty(network, channel_idx, ttys[j]); if (secondary_channel_idx != -1) diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index d593a7d..99cf22e 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -1611,7 +1611,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev, goto errunri; for (index = 0; index < board->port_count; index++) - tty_register_device(isicom_normal, board->index * 16 + index, + tty_port_register_device(&board->ports[index].port, + isicom_normal, board->index * 16 + index, &pdev->dev); return 0; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index e64fe40..8bc2651 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -2625,7 +2625,8 @@ static int __devinit mxser_probe(struct pci_dev *pdev, goto err_rel3; for (i = 0; i < brd->info->nports; i++) - tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); + tty_port_register_device(&brd->ports[i].port, mxvar_sdriver, + brd->idx + i, &pdev->dev); pci_set_drvdata(pdev, brd); @@ -2722,7 +2723,8 @@ static int __init mxser_module_init(void) brd->idx = m * MXSER_PORTS_PER_BOARD; for (i = 0; i < brd->info->nports; i++) - tty_register_device(mxvar_sdriver, brd->idx + i, NULL); + tty_port_register_device(&brd->ports[i].port, + mxvar_sdriver, brd->idx + i, NULL); m++; } diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index e7592f9..b917c94 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1473,8 +1473,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, port->dc = dc; tty_port_init(&port->port); port->port.ops = &noz_tty_port_ops; - tty_dev = tty_register_device(ntty_driver, dc->index_start + i, - &pdev->dev); + tty_dev = tty_port_register_device(&port->port, ntty_driver, + dc->index_start + i, &pdev->dev); if (IS_ERR(tty_dev)) { ret = PTR_ERR(tty_dev); diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 016984a..9700d34 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -704,8 +704,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) spin_lock_init(&info->slock); mutex_init(&info->write_mtx); rp_table[line] = info; - tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev : - NULL); + tty_port_register_device(&info->port, rocket_driver, line, + pci_dev ? &pci_dev->dev : NULL); } /* diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 144cd39..3f0c256 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -800,8 +800,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) tty_port_init(pport); pport->ops = &ifx_tty_port_ops; ifx_dev->minor = IFX_SPI_TTY_ID; - ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor, - &ifx_dev->spi_dev->dev); + ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv, + ifx_dev->minor, &ifx_dev->spi_dev->dev); if (IS_ERR(ifx_dev->tty_dev)) { dev_dbg(&ifx_dev->spi_dev->dev, "%s: registering tty device failed", __func__); diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c index b25e6ee..925d1fa 100644 --- a/drivers/tty/serial/msm_smd_tty.c +++ b/drivers/tty/serial/msm_smd_tty.c @@ -223,9 +223,11 @@ static int __init smd_tty_init(void) return ret; for (i = 0; i < smd_tty_channels_len; i++) { - tty_port_init(&smd_tty[smd_tty_channels[i].id].port); - smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops; - tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0); + struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port; + tty_port_init(port); + port->ops = &smd_tty_port_ops; + tty_port_register_device(port, smd_tty_driver, + smd_tty_channels[i].id, NULL); } return 0; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d98b1bd..5b308c8 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2346,7 +2346,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); + tty_dev = tty_port_register_device(port, drv->tty_driver, uport->line, + uport->dev); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 9130253..45f6136 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3689,8 +3689,11 @@ static void device_init(int adapter_num, struct pci_dev *pdev) } } - for (i=0; i < port_count; ++i) - tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev)); + for (i = 0; i < port_count; ++i) { + struct slgt_info *info = port_array[i]; + tty_port_register_device(&info->port, serial_driver, info->line, + &info->pdev->dev); + } } static int __devinit init_one(struct pci_dev *dev, diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 18f4e62..455ef16 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1298,7 +1298,8 @@ skip_countries: usb_set_intfdata(data_interface, acm); usb_get_intf(control_interface); - tty_register_device(acm_tty_driver, minor, &control_interface->dev); + tty_port_register_device(&acm->port, acm_tty_driver, minor, + &control_interface->dev); return 0; alloc_fail7: diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 5b3f5ff..2b5534c2 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -1129,7 +1129,8 @@ int gserial_setup(struct usb_gadget *g, unsigned count) for (i = 0; i < count; i++) { struct device *tty_dev; - tty_dev = tty_register_device(gs_tty_driver, i, &g->dev); + tty_dev = tty_port_register_device(&ports[i].port->port, + gs_tty_driver, i, &g->dev); if (IS_ERR(tty_dev)) pr_warning("%s: no classdev for port %d, err %ld\n", __func__, i, PTR_ERR(tty_dev)); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index b54c86a..18a80b9 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -278,8 +278,8 @@ out: if (err < 0) goto free; - dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); - + dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver, + dev->id, NULL); if (IS_ERR(dev->tty_dev)) { err = PTR_ERR(dev->tty_dev); list_del(&dev->list); -- cgit v0.10.2 From c4d6ebeb7d78ea8eabd5efe9ef876fe371cb5f4b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:48 +0200 Subject: TTY: automatically create nodes for some drivers This looks like it was a mistake not to create device nodes for these drivers. Let us create them from now on. It will be necessary to call tty_register_device some way, either by tty_register_driver implicitly or to call tty_register_device proper. Signed-off-by: Jiri Slaby Cc: netdev@vger.kernel.org Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Cc: linux-cris-kernel@axis.com Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 7a61ef6..576ce4b 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1782,7 +1782,7 @@ isdn_tty_modem_init(void) m->tty_modem->subtype = SERIAL_TYPE_NORMAL; m->tty_modem->init_termios = tty_std_termios; m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + m->tty_modem->flags = TTY_DRIVER_REAL_RAW; m->tty_modem->driver_name = "isdn_tty"; tty_set_operations(m->tty_modem, &modem_ops); retval = tty_register_driver(m->tty_modem); diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 215037c..f2b8c6c 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1781,7 +1781,7 @@ static int __init tty3270_init(void) driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; - driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV; + driver->flags = TTY_DRIVER_RESET_TERMIOS; tty_set_operations(driver, &tty3270_ops); ret = tty_register_driver(driver); if (ret) { diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index a770b10..5ecec3b 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -4443,7 +4443,7 @@ static int __init rs_init(void) B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ driver->init_termios.c_ispeed = 115200; driver->init_termios.c_ospeed = 115200; - driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &rs_ops); serial_driver = driver; -- cgit v0.10.2 From 72a33bf58c50892bce7ee4f58d487e818dec1c7e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:49 +0200 Subject: TTY: tty_port, add some documentation I forgot to document tty_port_register_device and tty_port_install when they were added. Fix it now. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 5246763..c2f0592 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -33,6 +33,17 @@ void tty_port_init(struct tty_port *port) } EXPORT_SYMBOL(tty_port_init); +/** + * tty_port_register_device - register tty device + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * @device: parent if exists, otherwise NULL + * + * It is the same as tty_register_device except the provided @port is linked to + * a concrete tty specified by @index. Use this or tty_port_install (or both). + * Call tty_port_link_device as a last resort. + */ struct device *tty_port_register_device(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device) @@ -422,6 +433,16 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty, } EXPORT_SYMBOL(tty_port_close); +/** + * tty_port_install - generic tty->ops->install handler + * @port: tty_port of the device + * @driver: tty_driver for this device + * @tty: tty to be installed + * + * It is the same as tty_standard_install except the provided @port is linked + * to a concrete tty specified by @tty. Use this or tty_port_register_device + * (or both). Call tty_port_link_device as a last resort. + */ int tty_port_install(struct tty_port *port, struct tty_driver *driver, struct tty_struct *tty) { -- cgit v0.10.2 From 2cb4ca0208722836e921d5ba780b09f29d4026b8 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:50 +0200 Subject: TTY: add tty_port_link_device This is for those drivers which do not have dynamic device creation (do not call tty_port_register_device) and do not want to implement tty->ops->install (will not call tty_port_install). They still have to provide the link somehow though. And this newly added function is exactly to serve that purpose. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index c2f0592..96302f4 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -34,6 +34,26 @@ void tty_port_init(struct tty_port *port) EXPORT_SYMBOL(tty_port_init); /** + * tty_port_link_device - link tty and tty_port + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * + * Provide the tty layer wit ha link from a tty (specified by @index) to a + * tty_port (@port). Use this only if neither tty_port_register_device nor + * tty_port_install is used in the driver. If used, this has to be called before + * tty_register_driver. + */ +void tty_port_link_device(struct tty_port *port, + struct tty_driver *driver, unsigned index) +{ + if (WARN_ON(index >= driver->num)) + return; + driver->ports[index] = port; +} +EXPORT_SYMBOL_GPL(tty_port_link_device); + +/** * tty_port_register_device - register tty device * @port: tty_port of the device * @driver: tty_driver for this device @@ -48,7 +68,7 @@ struct device *tty_port_register_device(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device) { - driver->ports[index] = port; + tty_port_link_device(port, driver, index); return tty_register_device(driver, index, device); } EXPORT_SYMBOL_GPL(tty_port_register_device); diff --git a/include/linux/tty.h b/include/linux/tty.h index acca24b..69a787f 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -497,6 +497,8 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay); #define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock)) extern void tty_port_init(struct tty_port *port); +extern void tty_port_link_device(struct tty_port *port, + struct tty_driver *driver, unsigned index); extern struct device *tty_port_register_device(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device); -- cgit v0.10.2 From b19e2ca77ee4becadc85341bb0c1cee454dd4fd5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:51 +0200 Subject: TTY: use tty_port_link_device So now for those drivers that can use neither tty_port_install nor tty_port_register_driver but still have tty_port available before tty_register_driver we use newly added tty_port_link_device. The rest of the drivers that still do not provide tty_struct <-> tty_port link will have to be converted to implement tty->ops->install. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 3ea8094..5d58652 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -223,6 +223,7 @@ srmcons_init(void) driver->subtype = SYSTEM_TYPE_SYSCONS; driver->init_termios = tty_std_termios; tty_set_operations(driver, &srmcons_ops); + tty_port_link_device(&srmcons_singleton.port, driver, 0); err = tty_register_driver(driver); if (err) { put_tty_driver(driver); diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 1ce97f4..ec536e4 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -545,6 +545,7 @@ static int __init simrs_init(void) /* the port is imaginary */ printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq); + tty_port_link_device(&state->port, hp_simserial_driver, 0); retval = tty_register_driver(hp_simserial_driver); if (retval) { printk(KERN_ERR "Couldn't register simserial driver\n"); diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index 47341aa..8823863 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -202,6 +202,7 @@ static int __init pdc_console_tty_driver_init(void) pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops); + tty_port_link_device(&tty_port, pdc_console_tty_driver, 0); err = tty_register_driver(pdc_console_tty_driver); if (err) { diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index f9726f6..2cd3d3a 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -223,6 +223,7 @@ int __init rs_init(void) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &serial_ops); + tty_port_link_device(&serial_port, serial_driver, 0); if (tty_register_driver(serial_driver)) panic("Couldn't register serial driver\n"); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 9e6272f..561f8aa 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -198,6 +198,7 @@ static int __init ttyprintk_init(void) ttyprintk_driver->init_termios = tty_std_termios; ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; tty_set_operations(ttyprintk_driver, &ttyprintk_ops); + tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0); ret = tty_register_driver(ttyprintk_driver); if (ret < 0) { diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 0792c85..30ec09e 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -567,6 +567,7 @@ sclp_tty_init(void) driver->init_termios.c_lflag = ISIG | ECHO; driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &sclp_ops); + tty_port_link_device(&sclp_port, driver, 0); rc = tty_register_driver(driver); if (rc) { put_tty_driver(driver); diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index edfc0fd..7e60f3d 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -691,6 +691,7 @@ static int __init sclp_vt220_tty_init(void) driver->init_termios = tty_std_termios; driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &sclp_vt220_ops); + tty_port_link_device(&sclp_vt220_port, driver, 0); rc = tty_register_driver(driver); if (rc) diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 998731f..2b7535d 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1710,10 +1710,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &serial_ops); - error = tty_register_driver(serial_driver); - if (error) - goto fail_put_tty_driver; - state = rs_table; state->port = (int)&custom.serdatr; /* Just to give it a value */ state->custom_divisor = 0; @@ -1724,6 +1720,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev) state->icount.overrun = state->icount.brk = 0; tty_port_init(&state->tport); state->tport.ops = &amiga_port_ops; + tty_port_link_device(&state->tport, serial_driver, 0); + + error = tty_register_driver(serial_driver); + if (error) + goto fail_put_tty_driver; printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n"); diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 61fc74f..02b7d3a 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -263,6 +263,7 @@ static int __init bfin_jc_init(void) bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL; bfin_jc_driver->init_termios = tty_std_termios; tty_set_operations(bfin_jc_driver, &bfin_jc_ops); + tty_port_link_device(&port, bfin_jc_driver, 0); ret = tty_register_driver(bfin_jc_driver); if (ret) diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 6f5bc49..0083bc1 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -1080,6 +1080,8 @@ static int __init hvsi_init(void) struct hvsi_struct *hp = &hvsi_ports[i]; int ret = 1; + tty_port_link_device(&hp->port, hvsi_driver, i); + ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp); if (ret) printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index cc4c092..66c38a3 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -1189,12 +1189,6 @@ rs68328_init(void) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &rs_ops); - if (tty_register_driver(serial_driver)) { - put_tty_driver(serial_driver); - printk(KERN_ERR "Couldn't register serial driver\n"); - return -ENOMEM; - } - local_irq_save(flags); for(i=0;itport, serial_driver, i); } local_irq_restore(flags); + + if (tty_register_driver(serial_driver)) { + put_tty_driver(serial_driver); + printk(KERN_ERR "Couldn't register serial driver\n"); + return -ENOMEM; + } + return 0; } diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 5ecec3b..35ee6a2 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -4447,10 +4447,8 @@ static int __init rs_init(void) tty_set_operations(driver, &rs_ops); serial_driver = driver; - if (tty_register_driver(driver)) - panic("Couldn't register serial driver\n"); - /* do some initializing for the separate ports */ + /* do some initializing for the separate ports */ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { if (info->enabled) { if (cris_request_io_interface(info->io_if, @@ -4502,7 +4500,12 @@ static int __init rs_init(void) printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n", serial_driver->name, info->line, info->ioport); } + tty_port_link_device(&info->port, driver, i); } + + if (tty_register_driver(driver)) + panic("Couldn't register serial driver\n"); + #ifdef CONFIG_ETRAX_FAST_TIMER #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER memset(fast_timers, 0, sizeof(fast_timers)); -- cgit v0.10.2 From 737586fe51e6d0031f83d781c0cb2f3abf8caada Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:52 +0200 Subject: TTY: synclink_cs, sanitize fail paths We will need to change the order of tty and pcmcia drivers initializations (see the reason later in this series). And the fail path handling is currently performed in a separate function that as well takes care of proper deinitialization in module_exit. It is hard to read and will need to be adjusted by our changes anyway. Instead, get rid of this helper function and do the fail paths handling directly in the init function. (And move the body of the function to module_exit.) Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index d0cbd29..0606586 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2798,23 +2798,6 @@ static const struct tty_operations mgslpc_ops = { .proc_fops = &mgslpc_proc_fops, }; -static void synclink_cs_cleanup(void) -{ - int rc; - - while(mgslpc_device_list) - mgslpc_remove_device(mgslpc_device_list); - - if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - put_tty_driver(serial_driver); - } - - pcmcia_unregister_driver(&mgslpc_driver); -} - static int __init synclink_cs_init(void) { int rc; @@ -2830,7 +2813,7 @@ static int __init synclink_cs_init(void) serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); if (!serial_driver) { rc = -ENOMEM; - goto error; + goto err_pcmcia_drv; } /* Initialize the tty_driver structure */ @@ -2850,25 +2833,29 @@ static int __init synclink_cs_init(void) if ((rc = tty_register_driver(serial_driver)) < 0) { printk("%s(%d):Couldn't register serial driver\n", __FILE__,__LINE__); - put_tty_driver(serial_driver); - serial_driver = NULL; - goto error; + goto err_put_tty; } printk("%s %s, tty major#%d\n", driver_name, driver_version, serial_driver->major); - return 0; - -error: - synclink_cs_cleanup(); - return rc; + return 0; +err_put_tty: + put_tty_driver(serial_driver); +err_pcmcia_drv: + pcmcia_unregister_driver(&mgslpc_driver); + return rc; } static void __exit synclink_cs_exit(void) { - synclink_cs_cleanup(); + while (mgslpc_device_list) + mgslpc_remove_device(mgslpc_device_list); + + tty_unregister_driver(serial_driver); + put_tty_driver(serial_driver); + pcmcia_unregister_driver(&mgslpc_driver); } module_init(synclink_cs_init); -- cgit v0.10.2 From 16a1065f2113b2c068ea108a681fb6b1f3a02ce0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:53 +0200 Subject: TTY: synclink_cs, use dynamic tty devices This allows us to provide the tty layer with information about tty_port for each link. And it also allows us to get rid of the remove_device loop in synclink_cs_exit because we had to reorder pcmcia and tty driver registration in init. This was because we need to have serial_driver initialized when calling tty_port_register_device from pcmcia ->probe. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 0606586..ce277f7 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2731,6 +2731,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info) #if SYNCLINK_GENERIC_HDLC hdlcdev_init(info); #endif + tty_port_register_device(&info->port, serial_driver, info->line, + &info->p_dev.dev); } static void mgslpc_remove_device(MGSLPC_INFO *remove_info) @@ -2744,6 +2746,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info) last->next_device = info->next_device; else mgslpc_device_list = info->next_device; + tty_unregister_device(serial_driver, info->line); #if SYNCLINK_GENERIC_HDLC hdlcdev_exit(info); #endif @@ -2807,13 +2810,12 @@ static int __init synclink_cs_init(void) BREAKPOINT(); } - if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0) - return rc; - - serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); + serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); if (!serial_driver) { rc = -ENOMEM; - goto err_pcmcia_drv; + goto err; } /* Initialize the tty_driver structure */ @@ -2827,7 +2829,6 @@ static int __init synclink_cs_init(void) serial_driver->init_termios = tty_std_termios; serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &mgslpc_ops); if ((rc = tty_register_driver(serial_driver)) < 0) { @@ -2836,26 +2837,28 @@ static int __init synclink_cs_init(void) goto err_put_tty; } + rc = pcmcia_register_driver(&mgslpc_driver); + if (rc < 0) + goto err_unreg_tty; + printk("%s %s, tty major#%d\n", driver_name, driver_version, serial_driver->major); return 0; +err_unreg_tty: + tty_unregister_driver(serial_driver); err_put_tty: put_tty_driver(serial_driver); -err_pcmcia_drv: - pcmcia_unregister_driver(&mgslpc_driver); +err: return rc; } static void __exit synclink_cs_exit(void) { - while (mgslpc_device_list) - mgslpc_remove_device(mgslpc_device_list); - + pcmcia_unregister_driver(&mgslpc_driver); tty_unregister_driver(serial_driver); put_tty_driver(serial_driver); - pcmcia_unregister_driver(&mgslpc_driver); } module_init(synclink_cs_init); -- cgit v0.10.2 From cc93441eed0d39af9d99ba1642b9f733b195435c Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:54 +0200 Subject: TTY: synclink_cs, final cleanup in synclink_cs_init * use for indentation * add KERN_* to printks * no more assignments in if's like if ((rc = function())) Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index ce277f7..923c3a4 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2803,47 +2803,46 @@ static const struct tty_operations mgslpc_ops = { static int __init synclink_cs_init(void) { - int rc; + int rc; - if (break_on_load) { - mgslpc_get_text_ptr(); - BREAKPOINT(); - } + if (break_on_load) { + mgslpc_get_text_ptr(); + BREAKPOINT(); + } - serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, - TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV); - if (!serial_driver) { - rc = -ENOMEM; - goto err; - } + serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (!serial_driver) { + rc = -ENOMEM; + goto err; + } - /* Initialize the tty_driver structure */ - - serial_driver->driver_name = "synclink_cs"; - serial_driver->name = "ttySLP"; - serial_driver->major = ttymajor; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty_set_operations(serial_driver, &mgslpc_ops); - - if ((rc = tty_register_driver(serial_driver)) < 0) { - printk("%s(%d):Couldn't register serial driver\n", - __FILE__,__LINE__); - goto err_put_tty; - } + /* Initialize the tty_driver structure */ + serial_driver->driver_name = "synclink_cs"; + serial_driver->name = "ttySLP"; + serial_driver->major = ttymajor; + serial_driver->minor_start = 64; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tty_set_operations(serial_driver, &mgslpc_ops); + + rc = tty_register_driver(serial_driver); + if (rc < 0) { + printk(KERN_ERR "%s(%d):Couldn't register serial driver\n", + __FILE__, __LINE__); + goto err_put_tty; + } rc = pcmcia_register_driver(&mgslpc_driver); if (rc < 0) goto err_unreg_tty; - printk("%s %s, tty major#%d\n", - driver_name, driver_version, - serial_driver->major); + printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version, + serial_driver->major); return 0; err_unreg_tty: -- cgit v0.10.2 From 793be8984fb979ae8887609862842cbb1f60bfaf Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:55 +0200 Subject: TTY: moxa, convert to dynamic device This allows us to provide the tty layer with information about tty_port for each link. We also provide a tty_port for the service port. For this one we allow only ioctl, so this is pretty ugly. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 89cc934..9dffc72 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -169,6 +169,7 @@ static DEFINE_SPINLOCK(moxa_lock); static unsigned long baseaddr[MAX_BOARDS]; static unsigned int type[MAX_BOARDS]; static unsigned int numports[MAX_BOARDS]; +static struct tty_port moxa_service_port; MODULE_AUTHOR("William Chen"); MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); @@ -834,7 +835,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) const struct firmware *fw; const char *file; struct moxa_port *p; - unsigned int i; + unsigned int i, first_idx; int ret; brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports), @@ -887,6 +888,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) mod_timer(&moxaTimer, jiffies + HZ / 50); spin_unlock_bh(&moxa_lock); + first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD; + for (i = 0; i < brd->numPorts; i++) + tty_port_register_device(&brd->ports[i].port, moxaDriver, + first_idx + i, dev); + return 0; err_free: kfree(brd->ports); @@ -896,7 +902,7 @@ err: static void moxa_board_deinit(struct moxa_board_conf *brd) { - unsigned int a, opened; + unsigned int a, opened, first_idx; mutex_lock(&moxa_openlock); spin_lock_bh(&moxa_lock); @@ -925,6 +931,10 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) mutex_lock(&moxa_openlock); } + first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD; + for (a = 0; a < brd->numPorts; a++) + tty_unregister_device(moxaDriver, first_idx + a); + iounmap(brd->basemem); brd->basemem = NULL; kfree(brd->ports); @@ -1031,7 +1041,12 @@ static int __init moxa_init(void) printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); - moxaDriver = alloc_tty_driver(MAX_PORTS + 1); + + tty_port_init(&moxa_service_port); + + moxaDriver = tty_alloc_driver(MAX_PORTS + 1, + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); if (!moxaDriver) return -ENOMEM; @@ -1044,8 +1059,9 @@ static int __init moxa_init(void) moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; moxaDriver->init_termios.c_ispeed = 9600; moxaDriver->init_termios.c_ospeed = 9600; - moxaDriver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(moxaDriver, &moxa_ops); + /* Having one more port only for ioctls is ugly */ + tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS); if (tty_register_driver(moxaDriver)) { printk(KERN_ERR "can't register MOXA Smartio tty driver!\n"); -- cgit v0.10.2 From 5920c2c9b9a16e86eb154fbb55d6034fbaad1b2b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:56 +0200 Subject: TTY: nfcon, add tty_port and link it Every tty driver needs tty_port for each line. So let us add one to nfcon too. And link it so that the tty layer knows about it. Signed-off-by: Jiri Slaby Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c index 8db25e8..16d170f 100644 --- a/arch/m68k/emu/nfcon.c +++ b/arch/m68k/emu/nfcon.c @@ -19,6 +19,7 @@ #include static int stderr_id; +static struct tty_port nfcon_tty_port; static struct tty_driver *nfcon_tty_driver; static void nfputs(const char *str, unsigned int count) @@ -119,6 +120,8 @@ static int __init nfcon_init(void) { int res; + tty_port_init(&nfcon_tty_port); + stderr_id = nf_get_id("NF_STDERR"); if (!stderr_id) return -ENODEV; @@ -135,6 +138,7 @@ static int __init nfcon_init(void) nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops); + tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0); res = tty_register_driver(nfcon_tty_driver); if (res) { pr_err("failed to register nfcon tty driver\n"); -- cgit v0.10.2 From 3ec0a17ef5f4ea922b10ebfdb99473c4d8d6120d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:57 +0200 Subject: TTY: con3215, unset raw3215[line] raw3215[line] is set in probe, but not unset in remove. This will lead to random crashes if the device is removed and the corresponding tty opened later. open would dereference freed memory. So set raw3215[line] to NULL in remove to fix that. Signed-off-by: Jiri Slaby Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 6c0116d..1655498 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -716,10 +716,17 @@ static int raw3215_probe (struct ccw_device *cdev) static void raw3215_remove (struct ccw_device *cdev) { struct raw3215_info *raw; + unsigned int line; ccw_device_set_offline(cdev); raw = dev_get_drvdata(&cdev->dev); if (raw) { + spin_lock(&raw3215_device_lock); + for (line = 0; line < NR_3215; line++) + if (raw3215[line] == raw) + break; + raw3215[line] = NULL; + spin_unlock(&raw3215_device_lock); dev_set_drvdata(&cdev->dev, NULL); raw3215_free_info(raw); } -- cgit v0.10.2 From d2281107457cacf44d60b8a97c5db1af27c3a716 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:58 +0200 Subject: TTY: con3215, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty Signed-off-by: Jiri Slaby Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 1655498..9ffb6d5 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -942,6 +942,19 @@ static int __init con3215_init(void) console_initcall(con3215_init); #endif +static int tty3215_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct raw3215_info *raw; + + raw = raw3215[tty->index]; + if (raw == NULL) + return -ENODEV; + + tty->driver_data = raw; + + return tty_port_install(&raw->port, driver, tty); +} + /* * tty3215_open * @@ -949,14 +962,9 @@ console_initcall(con3215_init); */ static int tty3215_open(struct tty_struct *tty, struct file * filp) { - struct raw3215_info *raw; + struct raw3215_info *raw = tty->driver_data; int retval; - raw = raw3215[tty->index]; - if (raw == NULL) - return -ENODEV; - - tty->driver_data = raw; tty_port_tty_set(&raw->port, tty); tty->low_latency = 0; /* don't use bottom half for pushing chars */ @@ -1117,6 +1125,7 @@ static void tty3215_start(struct tty_struct *tty) } static const struct tty_operations tty3215_ops = { + .install = tty3215_install, .open = tty3215_open, .close = tty3215_close, .write = tty3215_write, -- cgit v0.10.2 From f7e0405e7416424c2db2155949dca1daa0225089 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:47:59 +0200 Subject: TTY: i4l, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty The "tty->port = port" assignment is not needed anymore since it happens in tty_port_install implicitly. Signed-off-by: Jiri Slaby Cc: Karsten Keil Cc: netdev@vger.kernel.org Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 576ce4b..b817809 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * ------------------------------------------------------------ */ +static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty) +{ + modem_info *info = &dev->mdm.info[tty->index]; + + if (isdn_tty_paranoia_check(info, tty->name, __func__)) + return -ENODEV; + + tty->driver_data = info; + + return tty_port_install(&info->port, driver, tty); +} + /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into @@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static int isdn_tty_open(struct tty_struct *tty, struct file *filp) { - struct tty_port *port; - modem_info *info; + modem_info *info = tty->driver_data; + struct tty_port *port = &info->port; int retval; - info = &dev->mdm.info[tty->index]; - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open")) - return -ENODEV; - port = &info->port; #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, port->count); #endif port->count++; - tty->driver_data = info; port->tty = tty; - tty->port = port; /* * Start up serial port */ @@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m) } static const struct tty_operations modem_ops = { + .install = isdn_tty_install, .open = isdn_tty_open, .close = isdn_tty_close, .write = isdn_tty_write, -- cgit v0.10.2 From 8a3ad1047593f1f6f431140f7dd9748423c51cd1 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:48:00 +0200 Subject: TTY: synclink, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 991bae8..666aa14 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -3362,6 +3362,29 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, } /* end of block_til_ready() */ +static int mgsl_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct mgsl_struct *info; + int line = tty->index; + + /* verify range of specified line number */ + if (line >= mgsl_device_count) { + printk("%s(%d):mgsl_open with invalid line #%d.\n", + __FILE__, __LINE__, line); + return -ENODEV; + } + + /* find the info structure for the specified line */ + info = mgsl_device_list; + while (info && info->line != line) + info = info->next_device; + if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) + return -ENODEV; + tty->driver_data = info; + + return tty_port_install(&info->port, driver, tty); +} + /* mgsl_open() * * Called when a port is opened. Init and enable port. @@ -3374,26 +3397,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ static int mgsl_open(struct tty_struct *tty, struct file * filp) { - struct mgsl_struct *info; - int retval, line; + struct mgsl_struct *info = tty->driver_data; unsigned long flags; + int retval; - /* verify range of specified line number */ - line = tty->index; - if (line >= mgsl_device_count) { - printk("%s(%d):mgsl_open with invalid line #%d.\n", - __FILE__,__LINE__,line); - return -ENODEV; - } - - /* find the info structure for the specified line */ - info = mgsl_device_list; - while(info && info->line != line) - info = info->next_device; - if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) - return -ENODEV; - - tty->driver_data = info; info->port.tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) @@ -4297,6 +4304,7 @@ static struct mgsl_struct* mgsl_allocate_device(void) } /* end of mgsl_allocate_device()*/ static const struct tty_operations mgsl_ops = { + .install = mgsl_install, .open = mgsl_open, .close = mgsl_close, .write = mgsl_write, -- cgit v0.10.2 From ee3b48da84261ce37ef339e27e353a512c93ce5f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:48:01 +0200 Subject: TTY: synclinkmp, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 95fd4e2..53429c8 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -711,15 +711,11 @@ static void ldisc_receive_buf(struct tty_struct *tty, /* tty callbacks */ -/* Called when a port is opened. Init and enable port. - */ -static int open(struct tty_struct *tty, struct file *filp) +static int install(struct tty_driver *driver, struct tty_struct *tty) { SLMP_INFO *info; - int retval, line; - unsigned long flags; + int line = tty->index; - line = tty->index; if (line >= synclinkmp_device_count) { printk("%s(%d): open with invalid line #%d.\n", __FILE__,__LINE__,line); @@ -727,17 +723,30 @@ static int open(struct tty_struct *tty, struct file *filp) } info = synclinkmp_device_list; - while(info && info->line != line) + while (info && info->line != line) info = info->next_device; if (sanity_check(info, tty->name, "open")) return -ENODEV; - if ( info->init_error ) { + if (info->init_error) { printk("%s(%d):%s device is not allocated, init error=%d\n", - __FILE__,__LINE__,info->device_name,info->init_error); + __FILE__, __LINE__, info->device_name, + info->init_error); return -ENODEV; } tty->driver_data = info; + + return tty_port_install(&info->port, driver, tty); +} + +/* Called when a port is opened. Init and enable port. + */ +static int open(struct tty_struct *tty, struct file *filp) +{ + SLMP_INFO *info = tty->driver_data; + unsigned long flags; + int retval; + info->port.tty = tty; if (debug_level >= DEBUG_LEVEL_INFO) @@ -3881,6 +3890,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev) } static const struct tty_operations ops = { + .install = install, .open = open, .close = close, .write = write, -- cgit v0.10.2 From 9c650ffc27b444f5370ae5e8bc84df76584416a0 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:48:02 +0200 Subject: TTY: ircomm_tty, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty Signed-off-by: Jiri Slaby Cc: Samuel Ortiz Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 7a0d611..9668990 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -52,6 +52,8 @@ #include #include +static int ircomm_tty_install(struct tty_driver *driver, + struct tty_struct *tty); static int ircomm_tty_open(struct tty_struct *tty, struct file *filp); static void ircomm_tty_close(struct tty_struct * tty, struct file *filp); static int ircomm_tty_write(struct tty_struct * tty, @@ -82,6 +84,7 @@ static struct tty_driver *driver; static hashbin_t *ircomm_tty = NULL; static const struct tty_operations ops = { + .install = ircomm_tty_install, .open = ircomm_tty_open, .close = ircomm_tty_close, .write = ircomm_tty_write, @@ -374,21 +377,11 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, return retval; } -/* - * Function ircomm_tty_open (tty, filp) - * - * This routine is called when a particular tty device is opened. This - * routine is mandatory; if this routine is not filled in, the attempted - * open will fail with ENODEV. - */ -static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) + +static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) { struct ircomm_tty_cb *self; unsigned int line = tty->index; - unsigned long flags; - int ret; - - IRDA_DEBUG(2, "%s()\n", __func__ ); /* Check if instance already exists */ self = hashbin_lock_find(ircomm_tty, line, NULL); @@ -425,14 +418,30 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) tty->termios.c_oflag = 0; /* Insert into hash */ - /* FIXME there is a window from find to here */ hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); } + + return tty_port_install(&self->port, driver, tty); +} + +/* + * Function ircomm_tty_open (tty, filp) + * + * This routine is called when a particular tty device is opened. This + * routine is mandatory; if this routine is not filled in, the attempted + * open will fail with ENODEV. + */ +static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) +{ + struct ircomm_tty_cb *self = tty->driver_data; + unsigned long flags; + int ret; + + IRDA_DEBUG(2, "%s()\n", __func__ ); + /* ++ is not atomic, so this should be protected - Jean II */ spin_lock_irqsave(&self->port.lock, flags); self->port.count++; - - tty->driver_data = self; spin_unlock_irqrestore(&self->port.lock, flags); tty_port_tty_set(&self->port, tty); @@ -472,7 +481,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) } /* Check if this is a "normal" ircomm device, or an irlpt device */ - if (line < 0x10) { + if (self->line < 0x10) { self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE; self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */ /* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */ -- cgit v0.10.2 From 20cda6f25f9edaa26638fc32e88241af135d712d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:48:03 +0200 Subject: TTY: tty3270, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty In this case ->install is the only thing we want to do. We do not need ->open at all. See the tty->count > 1 check. And since we take a reference in ->install, we need also ->cleanup to drop the reference to a view. Final note, see that we leave raw3270_find_view in place. It is because views are removed even from module_exit. Signed-off-by: Jiri Slaby Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: linux-s390@vger.kernel.org Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index f2b8c6c..482ee02 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -842,17 +842,14 @@ static struct raw3270_fn tty3270_fn = { }; /* - * This routine is called whenever a 3270 tty is opened. + * This routine is called whenever a 3270 tty is opened first time. */ -static int -tty3270_open(struct tty_struct *tty, struct file * filp) +static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) { struct raw3270_view *view; struct tty3270 *tp; int i, rc; - if (tty->count > 1) - return 0; /* Check if the tty3270 is already there. */ view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR); @@ -865,7 +862,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp) /* why to reassign? */ tty_port_tty_set(&tp->port, tty); tp->inattr = TF_INPUT; - return 0; + return tty_port_install(&tp->port, driver, tty); } if (tty3270_max_index < tty->index + 1) tty3270_max_index = tty->index + 1; @@ -895,7 +892,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp) tty_port_tty_set(&tp->port, tty); tty->low_latency = 0; - tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; @@ -915,6 +911,15 @@ tty3270_open(struct tty_struct *tty, struct file * filp) kbd_ascebc(tp->kbd, tp->view.ascebc); raw3270_activate_view(&tp->view); + + rc = tty_port_install(&tp->port, driver, tty); + if (rc) { + raw3270_put_view(&tp->view); + return rc; + } + + tty->driver_data = tp; + return 0; } @@ -932,10 +937,17 @@ tty3270_close(struct tty_struct *tty, struct file * filp) if (tp) { tty->driver_data = NULL; tty_port_tty_set(&tp->port, NULL); - raw3270_put_view(&tp->view); } } +static void tty3270_cleanup(struct tty_struct *tty) +{ + struct tty3270 *tp = tty->driver_data; + + if (tp) + raw3270_put_view(&tp->view); +} + /* * We always have room. */ @@ -1737,7 +1749,8 @@ static long tty3270_compat_ioctl(struct tty_struct *tty, #endif static const struct tty_operations tty3270_ops = { - .open = tty3270_open, + .install = tty3270_install, + .cleanup = tty3270_cleanup, .close = tty3270_close, .write = tty3270_write, .put_char = tty3270_put_char, -- cgit v0.10.2 From bdb498c20040616e94b05c31a0ceb3e134b7e829 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:48:04 +0200 Subject: TTY: hvc_console, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty Since we take a reference to a port in ->install, we need also ->cleanup to drop that reference. Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 2d691eb..7f80f15 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -299,20 +299,33 @@ static void hvc_unthrottle(struct tty_struct *tty) hvc_kick(); } +static int hvc_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct hvc_struct *hp; + int rc; + + /* Auto increments kref reference if found. */ + if (!(hp = hvc_get_by_index(tty->index))) + return -ENODEV; + + tty->driver_data = hp; + + rc = tty_port_install(&hp->port, driver, tty); + if (rc) + tty_port_put(&hp->port); + return rc; +} + /* * The TTY interface won't be used until after the vio layer has exposed the vty * adapter to the kernel. */ static int hvc_open(struct tty_struct *tty, struct file * filp) { - struct hvc_struct *hp; + struct hvc_struct *hp = tty->driver_data; unsigned long flags; int rc = 0; - /* Auto increments kref reference if found. */ - if (!(hp = hvc_get_by_index(tty->index))) - return -ENODEV; - spin_lock_irqsave(&hp->port.lock, flags); /* Check and then increment for fast path open. */ if (hp->port.count++ > 0) { @@ -322,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) } /* else count == 0 */ spin_unlock_irqrestore(&hp->port.lock, flags); - tty->driver_data = hp; tty_port_tty_set(&hp->port, tty); if (hp->ops->notifier_add) @@ -389,6 +401,11 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp->vtermno, hp->port.count); spin_unlock_irqrestore(&hp->port.lock, flags); } +} + +static void hvc_cleanup(struct tty_struct *tty) +{ + struct hvc_struct *hp = tty->driver_data; tty_port_put(&hp->port); } @@ -792,8 +809,10 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) #endif static const struct tty_operations hvc_ops = { + .install = hvc_install, .open = hvc_open, .close = hvc_close, + .cleanup = hvc_cleanup, .write = hvc_write, .hangup = hvc_hangup, .unthrottle = hvc_unthrottle, -- cgit v0.10.2 From 97d150898592be8d5381ebc8d435526df38a2791 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:48:05 +0200 Subject: TTY: hvcs, clean hvcs_open a bit Make the code of hvcs_open a bit more readable by: - moving all assignments out of if's - redoing fail paths so that corresponding pieces are nearby - we need only one of retval and rc Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index d56788c..6f5c3be 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1109,11 +1109,10 @@ static struct hvcs_struct *hvcs_get_by_index(int index) static int hvcs_open(struct tty_struct *tty, struct file *filp) { struct hvcs_struct *hvcsd; - int rc, retval = 0; - unsigned long flags; - unsigned int irq; struct vio_dev *vdev; - unsigned long unit_address; + unsigned long unit_address, flags; + unsigned int irq; + int retval; if (tty->driver_data) goto fast_open; @@ -1122,7 +1121,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * Is there a vty-server that shares the same index? * This function increments the kref index. */ - if (!(hvcsd = hvcs_get_by_index(tty->index))) { + hvcsd = hvcs_get_by_index(tty->index); + if (!hvcsd) { printk(KERN_WARNING "HVCS: open failed, no device associated" " with tty->index %d.\n", tty->index); return -ENODEV; @@ -1130,9 +1130,14 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->connected == 0) - if ((retval = hvcs_partner_connect(hvcsd))) - goto error_release; + if (hvcsd->connected == 0) { + retval = hvcs_partner_connect(hvcsd); + if (retval) { + spin_unlock_irqrestore(&hvcsd->lock, flags); + printk(KERN_WARNING "HVCS: partner connect failed.\n"); + goto err_put; + } + } hvcsd->port.count = 1; hvcsd->port.tty = tty; @@ -1155,10 +1160,10 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * This must be done outside of the spinlock because it requests irqs * and will grab the spinlock and free the connection if it fails. */ - if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - tty_port_put(&hvcsd->port); + retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev); + if (retval) { printk(KERN_WARNING "HVCS: enable device failed.\n"); - return rc; + goto err_put; } goto open_success; @@ -1179,12 +1184,9 @@ open_success: hvcsd->vdev->unit_address ); return 0; - -error_release: - spin_unlock_irqrestore(&hvcsd->lock, flags); +err_put: tty_port_put(&hvcsd->port); - printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; } -- cgit v0.10.2 From 27bf7c43a19c66bdc96ee3ee5a67e3bc2d601736 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 7 Aug 2012 21:48:06 +0200 Subject: TTY: hvcs, add tty install This has two outcomes: * we give the TTY layer a tty_port * we do not find the info structure every time open is called on that tty >From now on, we only increase the reference count in ->install (and decrease in ->cleanup). Signed-off-by: Jiri Slaby Cc: linuxppc-dev@lists.ozlabs.org Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 6f5c3be..cab5c7a 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1102,11 +1102,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) return NULL; } -/* - * This is invoked via the tty_open interface when a user app connects to the - * /dev node. - */ -static int hvcs_open(struct tty_struct *tty, struct file *filp) +static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty) { struct hvcs_struct *hvcsd; struct vio_dev *vdev; @@ -1114,9 +1110,6 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) unsigned int irq; int retval; - if (tty->driver_data) - goto fast_open; - /* * Is there a vty-server that shares the same index? * This function increments the kref index. @@ -1139,7 +1132,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) } } - hvcsd->port.count = 1; + hvcsd->port.count = 0; hvcsd->port.tty = tty; tty->driver_data = hvcsd; @@ -1166,28 +1159,42 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) goto err_put; } - goto open_success; + retval = tty_port_install(&hvcsd->port, driver, tty); + if (retval) + goto err_irq; -fast_open: - hvcsd = tty->driver_data; + return 0; +err_irq: + spin_lock_irqsave(&hvcsd->lock, flags); + vio_disable_interrupts(hvcsd->vdev); + spin_unlock_irqrestore(&hvcsd->lock, flags); + free_irq(irq, hvcsd); +err_put: + tty_port_put(&hvcsd->port); + + return retval; +} + +/* + * This is invoked via the tty_open interface when a user app connects to the + * /dev node. + */ +static int hvcs_open(struct tty_struct *tty, struct file *filp) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + unsigned long flags; spin_lock_irqsave(&hvcsd->lock, flags); - tty_port_get(&hvcsd->port); hvcsd->port.count++; hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); -open_success: hvcs_kick(); printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", hvcsd->vdev->unit_address ); return 0; -err_put: - tty_port_put(&hvcsd->port); - - return retval; } static void hvcs_close(struct tty_struct *tty, struct file *filp) @@ -1238,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - tty_port_put(&hvcsd->port); return; } else if (hvcsd->port.count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" @@ -1247,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) } spin_unlock_irqrestore(&hvcsd->lock, flags); +} + +static void hvcs_cleanup(struct tty_struct * tty) +{ + struct hvcs_struct *hvcsd = tty->driver_data; + tty_port_put(&hvcsd->port); } @@ -1433,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty) } static const struct tty_operations hvcs_ops = { + .install = hvcs_install, .open = hvcs_open, .close = hvcs_close, + .cleanup = hvcs_cleanup, .hangup = hvcs_hangup, .write = hvcs_write, .write_room = hvcs_write_room, -- cgit v0.10.2 From a342ca1c78627c3a8b2a8c4e6d5f6ab1b88e6169 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 13 Aug 2012 10:18:09 +0200 Subject: TTY: mxser, fix invalid module_parm permissions 444 means 0674 and we do not definitely want that. Use S_IRUGO which is much more safer. Signed-off-by: Jiri Slaby Reported-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8bc2651..bb2da4c 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -2338,7 +2338,7 @@ static struct tty_port_operations mxser_port_ops = { */ static bool allow_overlapping_vector; -module_param(allow_overlapping_vector, bool, 444); +module_param(allow_overlapping_vector, bool, S_IRUGO); MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)"); static bool mxser_overlapping_vector(struct mxser_board *brd) -- cgit v0.10.2 From a33ba827460cdab644e907fc0c740dc7fde56c17 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 14 Aug 2012 10:23:08 +0200 Subject: TTY: synclink_cs, fix build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit "TTY: synclink_cs, use dynamic tty devices" added a call to tty_port_register_device with a proper device as the last argument. But it was not correct and it causes build failures: synclink_cs.c: In function ‘mgslpc_add_device’: synclink_cs.c:2735:16: error: request for member ‘dev’ in something not a structure or union info->p_dev is a pointer, so act as that. I wonder why my build scripts did not notice. I have to re-check them. Signed-off-by: Jiri Slaby Reported-by: Fengguang Wu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 923c3a4..d9335ae 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2732,7 +2732,7 @@ static void mgslpc_add_device(MGSLPC_INFO *info) hdlcdev_init(info); #endif tty_port_register_device(&info->port, serial_driver, info->line, - &info->p_dev.dev); + &info->p_dev->dev); } static void mgslpc_remove_device(MGSLPC_INFO *remove_info) -- cgit v0.10.2 From 640de636a1f149a92fe54f564ce931ec6b8418c6 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 14 Aug 2012 09:42:39 -0700 Subject: MIPS: OCTEON: Fix breakage due to 8250 changes. The changes in linux-next removing serial8250_register_port() cause OCTEON to fail to compile. Lets make OCTEON use the new serial8250_register_8250_port() instead. Signed-off-by: David Daney Cc: Alan Cox Acked-by: Ralf Baechle Signed-off-by: Greg Kroah-Hartman diff --git a/arch/mips/cavium-octeon/serial.c b/arch/mips/cavium-octeon/serial.c index 138b221..569f41b 100644 --- a/arch/mips/cavium-octeon/serial.c +++ b/arch/mips/cavium-octeon/serial.c @@ -47,40 +47,40 @@ static int __devinit octeon_serial_probe(struct platform_device *pdev) { int irq, res; struct resource *res_mem; - struct uart_port port; + struct uart_8250_port up; /* All adaptors have an irq. */ irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - memset(&port, 0, sizeof(port)); + memset(&up, 0, sizeof(up)); - port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; - port.type = PORT_OCTEON; - port.iotype = UPIO_MEM; - port.regshift = 3; - port.dev = &pdev->dev; + up.port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + up.port.type = PORT_OCTEON; + up.port.iotype = UPIO_MEM; + up.port.regshift = 3; + up.port.dev = &pdev->dev; if (octeon_is_simulation()) /* Make simulator output fast*/ - port.uartclk = 115200 * 16; + up.port.uartclk = 115200 * 16; else - port.uartclk = octeon_get_io_clock_rate(); + up.port.uartclk = octeon_get_io_clock_rate(); - port.serial_in = octeon_serial_in; - port.serial_out = octeon_serial_out; - port.irq = irq; + up.port.serial_in = octeon_serial_in; + up.port.serial_out = octeon_serial_out; + up.port.irq = irq; res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res_mem == NULL) { dev_err(&pdev->dev, "found no memory resource\n"); return -ENXIO; } - port.mapbase = res_mem->start; - port.membase = ioremap(res_mem->start, resource_size(res_mem)); + up.port.mapbase = res_mem->start; + up.port.membase = ioremap(res_mem->start, resource_size(res_mem)); - res = serial8250_register_port(&port); + res = serial8250_register_8250_port(&up); return res >= 0 ? 0 : res; } -- cgit v0.10.2 From 386d95b3ad6f6dad61d0be379873dca66595c1e4 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 14 Aug 2012 08:47:35 +0200 Subject: drivers/tty/moxa.c: fix error return code Convert a 0 error return code to a negative one, as returned elsewhere in the function. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e,e1,e2,e3,e4,x; @@ ( if (\(ret != 0\|ret < 0\) || ...) { ... return ...; } | ret = 0 ) ... when != ret = e1 *x = \(kmalloc\|kzalloc\|kcalloc\|devm_kzalloc\|ioremap\|ioremap_nocache\|devm_ioremap\|devm_ioremap_nocache\)(...); ... when != x = e2 when != ret = e3 *if (x == NULL || ...) { ... when != ret = e4 * return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 9dffc72..3b17a04 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -977,6 +977,7 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev, board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000); if (board->basemem == NULL) { dev_err(&pdev->dev, "can't remap io space 2\n"); + retval = -ENOMEM; goto err_reg; } -- cgit v0.10.2 From 6683549e4ba050cddd8fa88c3f1e53b825fdcb6d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 16 Aug 2012 12:01:33 +0100 Subject: 8250: add AgeStar AS-PRS2-009 Signed-off-by: Alan Cox Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=22502 Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 62e10fe..ad4bb8d 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1194,6 +1194,8 @@ pci_xr17c154_setup(struct serial_private *priv, #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d +#define PCI_VENDOR_ID_AGESTAR 0x5372 +#define PCI_DEVICE_ID_AGESTAR_9375 0x6872 #define PCI_VENDOR_ID_ASIX 0x9710 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ @@ -4189,6 +4191,12 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_omegapci }, /* + * AgeStar as-prs2-009 + */ + { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_2_115200 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL */ -- cgit v0.10.2 From e9490e93c1978b6669f3e993caa3189be13ce459 Mon Sep 17 00:00:00 2001 From: Stanislav Kozina Date: Thu, 16 Aug 2012 12:01:47 +0100 Subject: Remove BUG_ON from n_tty_read() Change the BUG_ON to WARN_ON and return in case of tty->read_buf==NULL. We want to track a couple of long standing reports of this but at the same time we can avoid killing the box. Signed-off-by: Stanislav Kozina Signed-off-by: Alan Cox Cc: Horses Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 6259242..8c0b7b4 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1742,7 +1742,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, do_it_again: - BUG_ON(!tty->read_buf); + if (WARN_ON(!tty->read_buf)) + return -EAGAIN; c = job_control(tty, file); if (c < 0) -- cgit v0.10.2 From 7e8ac7b23b67416700dfb8b4136a4e81ce675b48 Mon Sep 17 00:00:00 2001 From: xiaojin Date: Mon, 13 Aug 2012 13:43:15 +0100 Subject: n_gsm.c: Implement 3GPP27.010 DLC start-up procedure in MUX In 3GPP27.010 5.8.1, it defined: The TE multiplexer initiates the establishment of the multiplexer control channel by sending a SABM frame on DLCI 0 using the procedures of clause 5.4.1. Once the multiplexer channel is established other DLCs may be established using the procedures of clause 5.4.1. This patch implement 5.8.1 in MUX level, it make sure DLC0 is the first channel to be setup. [or for those not familiar with the specification: it was possible to try and open a data connection while the control channel was not yet fully open, which is a spec violation and confuses some modems] Signed-off-by: xiaojin Tested-by: Yin, Fengwei [tweaked the order we check things and error code] Signed-off-by: Alan Cox Cc: The Horsebox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 3778687..0988aaa 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2889,6 +2889,10 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty) gsm = gsm_mux[mux]; if (gsm->dead) return -EL2HLT; + /* If DLCI 0 is not yet fully open return an error. This is ok from a locking + perspective as we don't have to worry about this if DLCI0 is lost */ + if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) + return -EL2NSYNC; dlci = gsm->dlci[line]; if (dlci == NULL) { alloc = true; -- cgit v0.10.2 From 192b6041e75bb4a2aae73834037038cea139a92d Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:43:36 +0100 Subject: n_gsm: uplink SKBs accumulate on list gsm_dlci_data_kick will not call any output function if tx_bytes > THRESH_LO furthermore it will call the output function only once if tx_bytes == 0 If the size of the IP writes are on the order of THRESH_LO we can get into a situation where skbs accumulate on the outbound list being starved for events to call the output function. gsm_dlci_data_kick now calls the sweep function when tx_bytes==0 Signed-off-by: Russ Gorby Tested-by: Kappel, LaurentX Signed-off-by: Alan Cox Cc: Hay and Water Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 0988aaa..c028f35 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -971,16 +971,19 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) static void gsm_dlci_data_kick(struct gsm_dlci *dlci) { unsigned long flags; + int sweep; spin_lock_irqsave(&dlci->gsm->tx_lock, flags); /* If we have nothing running then we need to fire up */ + sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO); if (dlci->gsm->tx_bytes == 0) { if (dlci->net) gsm_dlci_data_output_framed(dlci->gsm, dlci); else gsm_dlci_data_output(dlci->gsm, dlci); - } else if (dlci->gsm->tx_bytes < TX_THRESH_LO) - gsm_dlci_data_sweep(dlci->gsm); + } + if (sweep) + gsm_dlci_data_sweep(dlci->gsm); spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags); } -- cgit v0.10.2 From c01af4fec2c8f303d6b3354d44308d9e6bef8026 Mon Sep 17 00:00:00 2001 From: Frederic Berat Date: Mon, 13 Aug 2012 13:43:58 +0100 Subject: n_gsm : Flow control handling in Mux driver - Correcting handling of FCon/FCoff in order to respect 27.010 spec - Consider FCon/off will overide all dlci flow control except for dlci0 as we must be able to send control frames. - Dlci constipated handling according to FC, RTC and RTR values. - Modifying gsm_dlci_data_kick and gsm_dlci_data_sweep according to dlci constipated value Signed-off-by: Frederic Berat Signed-off-by: Russ Gorby Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c028f35..db15b56 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -673,6 +673,8 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, * * The tty device has called us to indicate that room has appeared in * the transmit queue. Ram more data into the pipe if we have any + * If we have been flow-stopped by a CMD_FCOFF, then we can only + * send messages on DLCI0 until CMD_FCON * * FIXME: lock against link layer control transmissions */ @@ -680,15 +682,19 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, static void gsm_data_kick(struct gsm_mux *gsm) { struct gsm_msg *msg = gsm->tx_head; + struct gsm_msg *free_msg; int len; int skip_sof = 0; - /* FIXME: We need to apply this solely to data messages */ - if (gsm->constipated) - return; - - while (gsm->tx_head != NULL) { - msg = gsm->tx_head; + while (msg) { + if (gsm->constipated && msg->addr) { + msg = msg->next; + continue; + } + if (gsm->dlci[msg->addr]->constipated) { + msg = msg->next; + continue; + } if (gsm->encoding != 0) { gsm->txframe[0] = GSM1_SOF; len = gsm_stuff_frame(msg->data, @@ -711,15 +717,19 @@ static void gsm_data_kick(struct gsm_mux *gsm) len - skip_sof) < 0) break; /* FIXME: Can eliminate one SOF in many more cases */ - gsm->tx_head = msg->next; - if (gsm->tx_head == NULL) - gsm->tx_tail = NULL; gsm->tx_bytes -= msg->len; - kfree(msg); /* For a burst of frames skip the extra SOF within the burst */ skip_sof = 1; + + if (gsm->tx_head == msg) + gsm->tx_head = msg->next; + free_msg = msg; + msg = msg->next; + kfree(free_msg); } + if (!gsm->tx_head) + gsm->tx_tail = NULL; } /** @@ -738,6 +748,8 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) u8 *dp = msg->data; u8 *fcs = dp + msg->len; + WARN_ONCE(dlci->constipated, "%s: queueing from a constipated DLCI", + __func__); /* Fill in the header */ if (gsm->encoding == 0) { if (msg->len < 128) @@ -944,6 +956,9 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) break; dlci = gsm->dlci[i]; if (dlci == NULL || dlci->constipated) { + if (dlci && (debug & 0x20)) + pr_info("%s: DLCI %d is constipated", + __func__, i); i++; continue; } @@ -973,6 +988,13 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci) unsigned long flags; int sweep; + if (dlci->constipated) { + if (debug & 0x20) + pr_info("%s: DLCI %d is constipated", + __func__, dlci->addr); + return; + } + spin_lock_irqsave(&dlci->gsm->tx_lock, flags); /* If we have nothing running then we need to fire up */ sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO); @@ -1030,6 +1052,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, { int mlines = 0; u8 brk = 0; + int fc; /* The modem status command can either contain one octet (v.24 signals) or two octets (v.24 signals + break signals). The length field will @@ -1041,19 +1064,27 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, else { brk = modem & 0x7f; modem = (modem >> 7) & 0x7f; - }; + } /* Flow control/ready to communicate */ - if (modem & MDM_FC) { + fc = (modem & MDM_FC) || !(modem & MDM_RTR); + if (fc && !dlci->constipated) { + if (debug & 0x20) + pr_info("%s: DLCI %d START constipated (tx_bytes=%d)", + __func__, dlci->addr, dlci->gsm->tx_bytes); /* Need to throttle our output on this device */ dlci->constipated = 1; - } - if (modem & MDM_RTC) { - mlines |= TIOCM_DSR | TIOCM_DTR; + } else if (!fc && dlci->constipated) { + if (debug & 0x20) + pr_info("%s: DLCI %d END constipated (tx_bytes=%d)", + __func__, dlci->addr, dlci->gsm->tx_bytes); dlci->constipated = 0; gsm_dlci_data_kick(dlci); } + /* Map modem bits */ + if (modem & MDM_RTC) + mlines |= TIOCM_DSR | TIOCM_DTR; if (modem & MDM_RTR) mlines |= TIOCM_RTS | TIOCM_CTS; if (modem & MDM_IC) @@ -1209,17 +1240,21 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, gsm_control_reply(gsm, CMD_TEST, data, clen); break; case CMD_FCON: - /* Modem wants us to STFU */ - gsm->constipated = 1; - gsm_control_reply(gsm, CMD_FCON, NULL, 0); - break; - case CMD_FCOFF: /* Modem can accept data again */ + if (debug & 0x20) + pr_info("%s: GSM END constipation", __func__); gsm->constipated = 0; - gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); + gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ gsm_data_kick(gsm); break; + case CMD_FCOFF: + /* Modem wants us to STFU */ + if (debug & 0x20) + pr_info("%s: GSM START constipation", __func__); + gsm->constipated = 1; + gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); + break; case CMD_MSC: /* Out of band modem line change indicator for a DLCI */ gsm_control_modem(gsm, data, clen); @@ -2276,7 +2311,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, gsm->error(gsm, *dp, flags); break; default: - WARN_ONCE("%s: unknown flag %d\n", + WARN_ONCE(1, "%s: unknown flag %d\n", tty_name(tty, buf), flags); break; } -- cgit v0.10.2 From 10c6c383e43565c9c6ec07ff8eb2825f8091bdf0 Mon Sep 17 00:00:00 2001 From: "samix.lebsir" Date: Mon, 13 Aug 2012 13:44:22 +0100 Subject: char: n_gsm: remove message filtering for contipated DLCI The design of uplink flow control in the mux driver is that for constipated channels data will backup into the per-channel fifos, and any messages that make it to the outbound message queue will still go out. Code was added to also stop messages that were in the outbound queue but this requires filtering through all the messages on the queue for stopped dlcis and changes some of the mux logic unneccessarily. The message fiiltering was removed to be in line w/ the original design as the message filtering does not provide any solution. Extra debug messages used during investigation were also removed. Signed-off-by: samix.lebsir Signed-off-by: Alan Cox Cc: Dressage Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index db15b56..5f68f2a 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -691,10 +691,6 @@ static void gsm_data_kick(struct gsm_mux *gsm) msg = msg->next; continue; } - if (gsm->dlci[msg->addr]->constipated) { - msg = msg->next; - continue; - } if (gsm->encoding != 0) { gsm->txframe[0] = GSM1_SOF; len = gsm_stuff_frame(msg->data, @@ -748,8 +744,6 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) u8 *dp = msg->data; u8 *fcs = dp + msg->len; - WARN_ONCE(dlci->constipated, "%s: queueing from a constipated DLCI", - __func__); /* Fill in the header */ if (gsm->encoding == 0) { if (msg->len < 128) @@ -956,9 +950,6 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) break; dlci = gsm->dlci[i]; if (dlci == NULL || dlci->constipated) { - if (dlci && (debug & 0x20)) - pr_info("%s: DLCI %d is constipated", - __func__, i); i++; continue; } @@ -988,12 +979,8 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci) unsigned long flags; int sweep; - if (dlci->constipated) { - if (debug & 0x20) - pr_info("%s: DLCI %d is constipated", - __func__, dlci->addr); + if (dlci->constipated) return; - } spin_lock_irqsave(&dlci->gsm->tx_lock, flags); /* If we have nothing running then we need to fire up */ @@ -1069,15 +1056,9 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, /* Flow control/ready to communicate */ fc = (modem & MDM_FC) || !(modem & MDM_RTR); if (fc && !dlci->constipated) { - if (debug & 0x20) - pr_info("%s: DLCI %d START constipated (tx_bytes=%d)", - __func__, dlci->addr, dlci->gsm->tx_bytes); /* Need to throttle our output on this device */ dlci->constipated = 1; } else if (!fc && dlci->constipated) { - if (debug & 0x20) - pr_info("%s: DLCI %d END constipated (tx_bytes=%d)", - __func__, dlci->addr, dlci->gsm->tx_bytes); dlci->constipated = 0; gsm_dlci_data_kick(dlci); } @@ -1241,8 +1222,6 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, break; case CMD_FCON: /* Modem can accept data again */ - if (debug & 0x20) - pr_info("%s: GSM END constipation", __func__); gsm->constipated = 0; gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ @@ -1250,8 +1229,6 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, break; case CMD_FCOFF: /* Modem wants us to STFU */ - if (debug & 0x20) - pr_info("%s: GSM START constipation", __func__); gsm->constipated = 1; gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); break; -- cgit v0.10.2 From 5e44708f75b0f8712da715d6babb0c21089b2317 Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:44:40 +0100 Subject: n_gsm: added interlocking for gsm_data_lock for certain code paths There were some locking holes in the management of the MUX's message queue for 2 code paths: 1) gsmld_write_wakeup 2) receipt of CMD_FCON flow-control message In both cases gsm_data_kick is called w/o locking so it can collide with other other instances of gsm_data_kick (pulling messages tx_tail) or potentially other instances of __gsm_data_queu (adding messages to tx_head) Changed to take the tx_lock in these 2 cases Signed-off-by: Russ Gorby Tested-by: Yin, Fengwei Signed-off-by: Alan Cox Cc: Riding School Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 5f68f2a..0d93e51 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1205,6 +1205,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, u8 *data, int clen) { u8 buf[1]; + unsigned long flags; + switch (command) { case CMD_CLD: { struct gsm_dlci *dlci = gsm->dlci[0]; @@ -1225,7 +1227,9 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, gsm->constipated = 0; gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_data_kick(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); break; case CMD_FCOFF: /* Modem wants us to STFU */ @@ -2392,12 +2396,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty) /* Queue poll */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + spin_lock_irqsave(&gsm->tx_lock, flags); gsm_data_kick(gsm); if (gsm->tx_bytes < TX_THRESH_LO) { - spin_lock_irqsave(&gsm->tx_lock, flags); gsm_dlci_data_sweep(gsm); - spin_unlock_irqrestore(&gsm->tx_lock, flags); } + spin_unlock_irqrestore(&gsm->tx_lock, flags); } /** -- cgit v0.10.2 From b4338e1efc339986cf6c0a3652906e914a86e2d3 Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:44:59 +0100 Subject: n_gsm: avoid accessing freed memory during CMD_FCOFF condition gsm_data_kick was recently modified to allow messages on the tx queue bound for DLCI0 to flow even during FCOFF conditions. Unfortunately we introduced a bug discovered by code inspection where subsequent list traversers can access freed memory if the DLCI0 messages were not all at the head of the list. Replaced singly linked tx list w/ a list_head and used provided interfaces for traversing and deleting members. Signed-off-by: Russ Gorby Tested-by: Yin, Fengwei Signed-off-by: Alan Cox Cc: Riding School Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 0d93e51..6f4f8d3 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -108,7 +108,7 @@ struct gsm_mux_net { */ struct gsm_msg { - struct gsm_msg *next; + struct list_head list; u8 addr; /* DLCI address + flags */ u8 ctrl; /* Control byte + flags */ unsigned int len; /* Length of data block (can be zero) */ @@ -245,8 +245,7 @@ struct gsm_mux { unsigned int tx_bytes; /* TX data outstanding */ #define TX_THRESH_HI 8192 #define TX_THRESH_LO 2048 - struct gsm_msg *tx_head; /* Pending data packets */ - struct gsm_msg *tx_tail; + struct list_head tx_list; /* Pending data packets */ /* Control messages */ struct timer_list t2_timer; /* Retransmit timer for commands */ @@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, m->len = len; m->addr = addr; m->ctrl = ctrl; - m->next = NULL; + INIT_LIST_HEAD(&m->list); return m; } @@ -681,16 +680,13 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, static void gsm_data_kick(struct gsm_mux *gsm) { - struct gsm_msg *msg = gsm->tx_head; - struct gsm_msg *free_msg; + struct gsm_msg *msg, *nmsg; int len; int skip_sof = 0; - while (msg) { - if (gsm->constipated && msg->addr) { - msg = msg->next; + list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { + if (gsm->constipated && msg->addr) continue; - } if (gsm->encoding != 0) { gsm->txframe[0] = GSM1_SOF; len = gsm_stuff_frame(msg->data, @@ -718,14 +714,9 @@ static void gsm_data_kick(struct gsm_mux *gsm) burst */ skip_sof = 1; - if (gsm->tx_head == msg) - gsm->tx_head = msg->next; - free_msg = msg; - msg = msg->next; - kfree(free_msg); + list_del(&msg->list); + kfree(msg); } - if (!gsm->tx_head) - gsm->tx_tail = NULL; } /** @@ -774,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) msg->data = dp; /* Add to the actual output queue */ - if (gsm->tx_tail) - gsm->tx_tail->next = msg; - else - gsm->tx_head = msg; - gsm->tx_tail = msg; + list_add_tail(&msg->list, &gsm->tx_list); gsm->tx_bytes += msg->len; gsm_data_kick(gsm); } @@ -2026,7 +2013,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm) { int i; struct gsm_dlci *dlci = gsm->dlci[0]; - struct gsm_msg *txq; + struct gsm_msg *txq, *utxq; struct gsm_control *gc; gsm->dead = 1; @@ -2061,11 +2048,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm) if (gsm->dlci[i]) gsm_dlci_release(gsm->dlci[i]); /* Now wipe the queues */ - for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) { - gsm->tx_head = txq->next; + list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) kfree(txq); - } - gsm->tx_tail = NULL; + INIT_LIST_HEAD(&gsm->tx_list); } EXPORT_SYMBOL_GPL(gsm_cleanup_mux); @@ -2176,6 +2161,7 @@ struct gsm_mux *gsm_alloc_mux(void) } spin_lock_init(&gsm->lock); kref_init(&gsm->ref); + INIT_LIST_HEAD(&gsm->tx_list); gsm->t1 = T1; gsm->t2 = T2; -- cgit v0.10.2 From 329e56780e514a7ab607bcb51a52ab0dc2669414 Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:45:15 +0100 Subject: n_gsm: replace kfree_skb w/ appropriate dev_* versions Drivers are supposed to use the dev_* versions of the kfree_skb interfaces. In a couple of cases we were called with IRQs disabled as well which kfree_skb() does not expect. Replaced kfree_skb calls w/ dev_kfree_skb and dev_kfree_skb_any Signed-off-by: Russ Gorby Tested-by: Yin, Fengwei Signed-off-by: Alan Cox Cc: Grooming Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 6f4f8d3..a8c82f5 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -879,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, if (len > gsm->mtu) { if (dlci->adaption == 3) { /* Over long frame, bin it */ - kfree_skb(dlci->skb); + dev_kfree_skb_any(dlci->skb); dlci->skb = NULL; return 0; } @@ -905,7 +905,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, skb_pull(dlci->skb, len); __gsm_data_queue(dlci, msg); if (last) { - kfree_skb(dlci->skb); + dev_kfree_skb_any(dlci->skb); dlci->skb = NULL; } return size; @@ -1674,7 +1674,7 @@ static void gsm_dlci_free(struct kref *ref) dlci->gsm->dlci[dlci->addr] = NULL; kfifo_free(dlci->fifo); while ((dlci->skb = skb_dequeue(&dlci->skb_list))) - kfree_skb(dlci->skb); + dev_kfree_skb(dlci->skb); kfree(dlci); } @@ -2013,7 +2013,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm) { int i; struct gsm_dlci *dlci = gsm->dlci[0]; - struct gsm_msg *txq, *utxq; + struct gsm_msg *txq, *ntxq; struct gsm_control *gc; gsm->dead = 1; -- cgit v0.10.2 From 88ed2a60610974443335c924d7cb8e5dcf9dbdc1 Mon Sep 17 00:00:00 2001 From: Russ Gorby Date: Mon, 13 Aug 2012 13:45:30 +0100 Subject: n_gsm: memory leak in uplink error path Uplink (TX) network data will go through gsm_dlci_data_output_framed there is a bug where if memory allocation fails, the skb which has already been pulled off the list will be lost. In addition TX skbs were being processed in LIFO order Fixed the memory leak, and changed to FIFO order processing Signed-off-by: Russ Gorby Tested-by: Kappel, LaurentX Signed-off-by: Alan Cox Cc: Showjumping Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index a8c82f5..3e210a4 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -868,7 +868,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, /* dlci->skb is locked by tx_lock */ if (dlci->skb == NULL) { - dlci->skb = skb_dequeue(&dlci->skb_list); + dlci->skb = skb_dequeue_tail(&dlci->skb_list); if (dlci->skb == NULL) return 0; first = 1; @@ -892,8 +892,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, /* FIXME: need a timer or something to kick this so it can't get stuck with no work outstanding and no buffer free */ - if (msg == NULL) + if (msg == NULL) { + skb_queue_tail(&dlci->skb_list, dlci->skb); + dlci->skb = NULL; return -ENOMEM; + } dp = msg->data; if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */ -- cgit v0.10.2 From c3a6344ae475763b6fb0fb2ec3639004f500d0f1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 16 Aug 2012 16:16:56 +0300 Subject: TTY: tty_alloc_driver() returns error pointers We changed these from alloc_tty_driver() to tty_alloc_driver() so the error handling needs to modified to check for IS_ERR() instead of NULL. Signed-off-by: Dan Carpenter Acked-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index d9335ae..5db08c7 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2813,8 +2813,8 @@ static int __init synclink_cs_init(void) serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); - if (!serial_driver) { - rc = -ENOMEM; + if (IS_ERR(serial_driver)) { + rc = PTR_ERR(serial_driver); goto err; } diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 561f8aa..af98f6d 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -187,8 +187,8 @@ static int __init ttyprintk_init(void) TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_UNNUMBERED_NODE); - if (!ttyprintk_driver) - return ret; + if (IS_ERR(ttyprintk_driver)) + return PTR_ERR(ttyprintk_driver); ttyprintk_driver->driver_name = "ttyprintk"; ttyprintk_driver->name = "ttyprintk"; diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 3b17a04..56e616b 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1048,8 +1048,8 @@ static int __init moxa_init(void) moxaDriver = tty_alloc_driver(MAX_PORTS + 1, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); - if (!moxaDriver) - return -ENOMEM; + if (IS_ERR(moxaDriver)) + return PTR_ERR(moxaDriver); moxaDriver->name = "ttyMX"; moxaDriver->major = ttymajor; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index f5a27c6..2bace84 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -448,14 +448,14 @@ static void __init legacy_pty_init(void) TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_ALLOC); - if (!pty_driver) + if (IS_ERR(pty_driver)) panic("Couldn't allocate pty driver"); pty_slave_driver = tty_alloc_driver(legacy_count, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_ALLOC); - if (!pty_slave_driver) + if (IS_ERR(pty_slave_driver)) panic("Couldn't allocate pty slave driver"); pty_driver->driver_name = "pty_master"; @@ -682,7 +682,7 @@ static void __init unix98_pty_init(void) TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | TTY_DRIVER_DYNAMIC_ALLOC); - if (!ptm_driver) + if (IS_ERR(ptm_driver)) panic("Couldn't allocate Unix98 ptm driver"); pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, TTY_DRIVER_RESET_TERMIOS | @@ -690,7 +690,7 @@ static void __init unix98_pty_init(void) TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | TTY_DRIVER_DYNAMIC_ALLOC); - if (!pts_driver) + if (IS_ERR(pts_driver)) panic("Couldn't allocate Unix98 pts driver"); ptm_driver->driver_name = "pty_master"; -- cgit v0.10.2 From 221ca778d677c5ec3a33385a3b6dd548174252a6 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 1 Aug 2012 12:00:20 +0400 Subject: serial: sc26xx: Fix compile breakage This patch fixes the following compile breakage: CC drivers/tty/serial/sc26xx.o drivers/tty/serial/sc26xx.c: In function 'read_sc_port': drivers/tty/serial/sc26xx.c:100: error: implicit declaration of function 'readb' drivers/tty/serial/sc26xx.c: In function 'write_sc_port': drivers/tty/serial/sc26xx.c:105: error: implicit declaration of function 'writeb' drivers/tty/serial/sc26xx.c: In function 'sc26xx_probe': drivers/tty/serial/sc26xx.c:652: error: implicit declaration of function 'ioremap_nocache' drivers/tty/serial/sc26xx.c:652: warning: assignment makes pointer from integer without a cast make[3]: *** [drivers/tty/serial/sc26xx.o] Error 1 make[2]: *** [drivers/tty/serial] Error 2 make[1]: *** [drivers/tty] Error 2 make: *** [drivers] Error 2 Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c index e0b4b0a..3992e48 100644 --- a/drivers/tty/serial/sc26xx.c +++ b/drivers/tty/serial/sc26xx.c @@ -20,6 +20,7 @@ #include #include #include +#include #if defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ -- cgit v0.10.2 From a92098a1cb7ec08c86d1b97d1831d8edaf26b1a2 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Sat, 28 Jul 2012 20:43:57 +0800 Subject: pch_uart: check kzalloc result in dma_handle_tx() Reported by coccinelle: drivers/tty/serial/pch_uart.c:979:1-14: alloc with no test, possible model on line 994 Signed-off-by: Fengguang Wu Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 558ce85..4cd6c23 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -979,6 +979,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) priv->tx_dma_use = 1; priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); + if (!priv->sg_tx_p) { + dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__); + return 0; + } sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */ sg = priv->sg_tx_p; -- cgit v0.10.2 From 9574f36fb801035f6ab0fbb1b53ce2c12c17d100 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 30 Jul 2012 10:30:26 +1000 Subject: OMAP/serial: Add support for driving a GPIO as DTR. OMAP hardware doesn't provide a phyisical DTR line, but some configurations may need a DTR line which tracks whether the device is open or not. So allow a gpio to be configured as the DTR line. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index c1b93c7..25d53b2 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -304,6 +304,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.dma_rx_timeout = info->dma_rx_timeout; omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; omap_up.autosuspend_timeout = info->autosuspend_timeout; + omap_up.DTR_gpio = info->DTR_gpio; + omap_up.DTR_inverted = info->DTR_inverted; + omap_up.DTR_present = info->DTR_present; pdata = &omap_up; pdata_size = sizeof(struct omap_uart_port_info); diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 1a52725..52d3de4 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -69,6 +69,9 @@ struct omap_uart_port_info { unsigned int dma_rx_timeout; unsigned int autosuspend_timeout; unsigned int dma_rx_poll_rate; + int DTR_gpio; + int DTR_inverted; + int DTR_present; int (*get_context_loss_count)(struct device *); void (*set_forceidle)(struct platform_device *); @@ -131,6 +134,10 @@ struct uart_omap_port { u32 errata; u8 wakeups_enabled; + int DTR_gpio; + int DTR_inverted; + int DTR_active; + struct pm_qos_request pm_qos_request; u32 latency; u32 calc_latency; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d3cda0c..aa603f2 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -507,6 +508,16 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) up->mcr |= mcr; serial_out(up, UART_MCR, up->mcr); pm_runtime_put(&up->pdev->dev); + + if (gpio_is_valid(up->DTR_gpio) && + !!(mctrl & TIOCM_DTR) != up->DTR_active) { + up->DTR_active = !up->DTR_active; + if (gpio_cansleep(up->DTR_gpio)) + schedule_work(&up->qos_work); + else + gpio_set_value(up->DTR_gpio, + up->DTR_active != up->DTR_inverted); + } } static void serial_omap_break_ctl(struct uart_port *port, int break_state) @@ -715,6 +726,9 @@ static void serial_omap_uart_qos_work(struct work_struct *work) qos_work); pm_qos_update_request(&up->pm_qos_request, up->latency); + if (gpio_is_valid(up->DTR_gpio)) + gpio_set_value_cansleep(up->DTR_gpio, + up->DTR_active != up->DTR_inverted); } static void @@ -1435,7 +1449,7 @@ static int serial_omap_probe(struct platform_device *pdev) struct uart_omap_port *up; struct resource *mem, *irq, *dma_tx, *dma_rx; struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; - int ret = -ENOSPC; + int ret; if (pdev->dev.of_node) omap_up_info = of_get_uart_port_info(&pdev->dev); @@ -1466,10 +1480,29 @@ static int serial_omap_probe(struct platform_device *pdev) if (!dma_tx) return -ENXIO; + if (gpio_is_valid(omap_up_info->DTR_gpio) && + omap_up_info->DTR_present) { + ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); + if (ret < 0) + return ret; + ret = gpio_direction_output(omap_up_info->DTR_gpio, + omap_up_info->DTR_inverted); + if (ret < 0) + return ret; + } + up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); if (!up) return -ENOMEM; + if (gpio_is_valid(omap_up_info->DTR_gpio) && + omap_up_info->DTR_present) { + up->DTR_gpio = omap_up_info->DTR_gpio; + up->DTR_inverted = omap_up_info->DTR_inverted; + } else + up->DTR_gpio = -EINVAL; + up->DTR_active = 0; + up->pdev = pdev; up->port.dev = &pdev->dev; up->port.type = PORT_OMAP; -- cgit v0.10.2 From f65444187a66bf54af32a10902877dd0326456d1 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 6 Aug 2012 19:42:32 +0400 Subject: serial: New serial driver MAX310X This driver is a replacement for a MAX3107 driver with a lot of improvements and new features. The main differences from the old version: - Using the regmap. - Using devm_XXX-related functions. - The use of threaded IRQ with IRQF_ONESHOT flag allows the driver to the hardware that supports only level IRQ. - Improved error handling of serial port, improved FIFO handling, improved hardware & software flow control. - Advanced flags allows turn on RS-485 mode (Auto direction control). - Ability to load multiple instances of drivers. - Added support for MAX3108. - GPIO support. - Driver is quite ready for adding I2C support and support other ICs with compatible registers set (MAX3109, MAX14830). Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 0020786..7b3d9de 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -257,12 +257,19 @@ config SERIAL_MAX3100 help MAX3100 chip support -config SERIAL_MAX3107 - tristate "MAX3107 support" +config SERIAL_MAX310X + bool "MAX310X support" depends on SPI select SERIAL_CORE + select REGMAP_SPI if SPI + default n help - MAX3107 chip support + This selects support for an advanced UART from Maxim (Dallas). + Supported ICs are MAX3107, MAX3108. + Each IC contains 128 words each of receive and transmit FIFO + that can be controlled through I2C or high-speed SPI. + + Say Y here if you want to support this ICs. config SERIAL_DZ bool "DECstation DZ serial driver" diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 8a5df38..2af9e52 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o obj-$(CONFIG_SERIAL_MAX3100) += max3100.o -obj-$(CONFIG_SERIAL_MAX3107) += max3107.o +obj-$(CONFIG_SERIAL_MAX310X) += max310x.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c deleted file mode 100644 index 17c7ba8..0000000 --- a/drivers/tty/serial/max3107.c +++ /dev/null @@ -1,1215 +0,0 @@ -/* - * max3107.c - spi uart protocol driver for Maxim 3107 - * Based on max3100.c - * by Christian Pellegrin - * and max3110.c - * by Feng Tang - * - * Copyright (C) Aavamobile 2009 - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "max3107.h" - -static const struct baud_table brg26_ext[] = { - { 300, MAX3107_BRG26_B300 }, - { 600, MAX3107_BRG26_B600 }, - { 1200, MAX3107_BRG26_B1200 }, - { 2400, MAX3107_BRG26_B2400 }, - { 4800, MAX3107_BRG26_B4800 }, - { 9600, MAX3107_BRG26_B9600 }, - { 19200, MAX3107_BRG26_B19200 }, - { 57600, MAX3107_BRG26_B57600 }, - { 115200, MAX3107_BRG26_B115200 }, - { 230400, MAX3107_BRG26_B230400 }, - { 460800, MAX3107_BRG26_B460800 }, - { 921600, MAX3107_BRG26_B921600 }, - { 0, 0 } -}; - -static const struct baud_table brg13_int[] = { - { 300, MAX3107_BRG13_IB300 }, - { 600, MAX3107_BRG13_IB600 }, - { 1200, MAX3107_BRG13_IB1200 }, - { 2400, MAX3107_BRG13_IB2400 }, - { 4800, MAX3107_BRG13_IB4800 }, - { 9600, MAX3107_BRG13_IB9600 }, - { 19200, MAX3107_BRG13_IB19200 }, - { 57600, MAX3107_BRG13_IB57600 }, - { 115200, MAX3107_BRG13_IB115200 }, - { 230400, MAX3107_BRG13_IB230400 }, - { 460800, MAX3107_BRG13_IB460800 }, - { 921600, MAX3107_BRG13_IB921600 }, - { 0, 0 } -}; - -static u32 get_new_brg(int baud, struct max3107_port *s) -{ - int i; - const struct baud_table *baud_tbl = s->baud_tbl; - - for (i = 0; i < 13; i++) { - if (baud == baud_tbl[i].baud) - return baud_tbl[i].new_brg; - } - - return 0; -} - -/* Perform SPI transfer for write/read of device register(s) */ -int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len) -{ - struct spi_message spi_msg; - struct spi_transfer spi_xfer; - - /* Initialize SPI ,message */ - spi_message_init(&spi_msg); - - /* Initialize SPI transfer */ - memset(&spi_xfer, 0, sizeof spi_xfer); - spi_xfer.len = len; - spi_xfer.tx_buf = tx; - spi_xfer.rx_buf = rx; - spi_xfer.speed_hz = MAX3107_SPI_SPEED; - - /* Add SPI transfer to SPI message */ - spi_message_add_tail(&spi_xfer, &spi_msg); - -#ifdef DBG_TRACE_SPI_DATA - { - int i; - pr_info("tx len %d:\n", spi_xfer.len); - for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) - pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]); - pr_info("\n"); - } -#endif - - /* Perform synchronous SPI transfer */ - if (spi_sync(s->spi, &spi_msg)) { - dev_err(&s->spi->dev, "spi_sync failure\n"); - return -EIO; - } - -#ifdef DBG_TRACE_SPI_DATA - if (spi_xfer.rx_buf) { - int i; - pr_info("rx len %d:\n", spi_xfer.len); - for (i = 0 ; i < spi_xfer.len && i < 32 ; i++) - pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]); - pr_info("\n"); - } -#endif - return 0; -} -EXPORT_SYMBOL_GPL(max3107_rw); - -/* Puts received data to circular buffer */ -static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data, - int len) -{ - struct uart_port *port = &s->port; - struct tty_struct *tty; - - if (!port->state) - return; - - tty = port->state->port.tty; - if (!tty) - return; - - /* Insert received data */ - tty_insert_flip_string(tty, data, len); - /* Update RX counter */ - port->icount.rx += len; -} - -/* Handle data receiving */ -static void max3107_handlerx(struct max3107_port *s, u16 rxlvl) -{ - int i; - int j; - int len; /* SPI transfer buffer length */ - u16 *buf; - u8 *valid_str; - - if (!s->rx_enabled) - /* RX is disabled */ - return; - - if (rxlvl == 0) { - /* RX fifo is empty */ - return; - } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) { - dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl); - /* Ensure sanity of RX level */ - rxlvl = MAX3107_RX_FIFO_SIZE; - } - if ((s->rxbuf == 0) || (s->rxstr == 0)) { - dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n"); - return; - } - buf = s->rxbuf; - valid_str = s->rxstr; - while (rxlvl) { - pr_debug("rxlvl %d\n", rxlvl); - /* Clear buffer */ - memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2)); - len = 0; - if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) { - /* First disable RX FIFO interrupt */ - pr_debug("Disabling RX INT\n"); - buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT; - buf[0] |= s->irqen_reg; - len++; - } - /* Just increase the length by amount of words in FIFO since - * buffer was zeroed and SPI transfer of 0x0000 means reading - * from RX FIFO - */ - len += rxlvl; - /* Append RX level query */ - buf[len] = MAX3107_RXFIFOLVL_REG; - len++; - - /* Perform the SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) { - dev_err(&s->spi->dev, "SPI transfer for RX h failed\n"); - return; - } - - /* Skip RX FIFO interrupt disabling word if it was added */ - j = ((len - 1) - rxlvl); - /* Read received words */ - for (i = 0; i < rxlvl; i++, j++) - valid_str[i] = (u8)buf[j]; - put_data_to_circ_buf(s, valid_str, rxlvl); - /* Get new RX level */ - rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK); - } - - if (s->rx_enabled) { - /* RX still enabled, re-enable RX FIFO interrupt */ - pr_debug("Enabling RX INT\n"); - buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT; - buf[0] |= s->irqen_reg; - if (max3107_rw(s, (u8 *)buf, NULL, 2)) - dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n"); - } - - /* Push the received data to receivers */ - if (s->port.state->port.tty) - tty_flip_buffer_push(s->port.state->port.tty); -} - - -/* Handle data sending */ -static void max3107_handletx(struct max3107_port *s) -{ - struct circ_buf *xmit = &s->port.state->xmit; - int i; - unsigned long flags; - int len; /* SPI transfer buffer length */ - u16 *buf; - - if (!s->tx_fifo_empty) - /* Don't send more data before previous data is sent */ - return; - - if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port)) - /* No data to send or TX is stopped */ - return; - - if (!s->txbuf) { - dev_warn(&s->spi->dev, "Txbuf isn't ready\n"); - return; - } - buf = s->txbuf; - /* Get length of data pending in circular buffer */ - len = uart_circ_chars_pending(xmit); - if (len) { - /* Limit to size of TX FIFO */ - if (len > MAX3107_TX_FIFO_SIZE) - len = MAX3107_TX_FIFO_SIZE; - - pr_debug("txlen %d\n", len); - - /* Update TX counter */ - s->port.icount.tx += len; - - /* TX FIFO will no longer be empty */ - s->tx_fifo_empty = 0; - - i = 0; - if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) { - /* First disable TX empty interrupt */ - pr_debug("Disabling TE INT\n"); - buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT; - buf[i] |= s->irqen_reg; - i++; - len++; - } - /* Add data to send */ - spin_lock_irqsave(&s->port.lock, flags); - for ( ; i < len ; i++) { - buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG); - buf[i] |= ((u16)xmit->buf[xmit->tail] & - MAX3107_SPI_TX_DATA_MASK); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } - spin_unlock_irqrestore(&s->port.lock, flags); - if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) { - /* Enable TX empty interrupt */ - pr_debug("Enabling TE INT\n"); - buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG); - s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT; - buf[i] |= s->irqen_reg; - i++; - len++; - } - if (!s->tx_enabled) { - /* Enable TX */ - pr_debug("Enable TX\n"); - buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - spin_lock_irqsave(&s->data_lock, flags); - s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT; - buf[i] |= s->mode1_reg; - spin_unlock_irqrestore(&s->data_lock, flags); - s->tx_enabled = 1; - i++; - len++; - } - - /* Perform the SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, len*2)) { - dev_err(&s->spi->dev, - "SPI transfer TX handling failed\n"); - return; - } - } - - /* Indicate wake up if circular buffer is getting low on data */ - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&s->port); - -} - -/* Handle interrupts - * Also reads and returns current RX FIFO level - */ -static u16 handle_interrupt(struct max3107_port *s) -{ - u16 buf[4]; /* Buffer for SPI transfers */ - u8 irq_status; - u16 rx_level; - unsigned long flags; - - /* Read IRQ status register */ - buf[0] = MAX3107_IRQSTS_REG; - /* Read status IRQ status register */ - buf[1] = MAX3107_STS_IRQSTS_REG; - /* Read LSR IRQ status register */ - buf[2] = MAX3107_LSR_IRQSTS_REG; - /* Query RX level */ - buf[3] = MAX3107_RXFIFOLVL_REG; - - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) { - dev_err(&s->spi->dev, - "SPI transfer for INTR handling failed\n"); - return 0; - } - - irq_status = (u8)buf[0]; - pr_debug("IRQSTS %x\n", irq_status); - rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK); - - if (irq_status & MAX3107_IRQ_LSR_BIT) { - /* LSR interrupt */ - if (buf[2] & MAX3107_LSR_RXTO_BIT) - /* RX timeout interrupt, - * handled by normal RX handling - */ - pr_debug("RX TO INT\n"); - } - - if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) { - /* Tx empty interrupt, - * disable TX and set tx_fifo_empty flag - */ - pr_debug("TE INT, disabling TX\n"); - buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - spin_lock_irqsave(&s->data_lock, flags); - s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT; - buf[0] |= s->mode1_reg; - spin_unlock_irqrestore(&s->data_lock, flags); - if (max3107_rw(s, (u8 *)buf, NULL, 2)) - dev_err(&s->spi->dev, "SPI transfer TX dis failed\n"); - s->tx_enabled = 0; - s->tx_fifo_empty = 1; - } - - if (irq_status & MAX3107_IRQ_RXFIFO_BIT) - /* RX FIFO interrupt, - * handled by normal RX handling - */ - pr_debug("RFIFO INT\n"); - - /* Return RX level */ - return rx_level; -} - -/* Trigger work thread*/ -static void max3107_dowork(struct max3107_port *s) -{ - if (!work_pending(&s->work) && !freezing(current) && !s->suspended) - queue_work(s->workqueue, &s->work); - else - dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n"); -} - -/* Work thread */ -static void max3107_work(struct work_struct *w) -{ - struct max3107_port *s = container_of(w, struct max3107_port, work); - u16 rxlvl = 0; - int len; /* SPI transfer buffer length */ - u16 buf[5]; /* Buffer for SPI transfers */ - unsigned long flags; - - /* Start by reading current RX FIFO level */ - buf[0] = MAX3107_RXFIFOLVL_REG; - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { - dev_err(&s->spi->dev, "SPI transfer RX lev failed\n"); - rxlvl = 0; - } else { - rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK); - } - - do { - pr_debug("rxlvl %d\n", rxlvl); - - /* Handle RX */ - max3107_handlerx(s, rxlvl); - rxlvl = 0; - - if (s->handle_irq) { - /* Handle pending interrupts - * We also get new RX FIFO level since new data may - * have been received while pushing received data to - * receivers - */ - s->handle_irq = 0; - rxlvl = handle_interrupt(s); - } - - /* Handle TX */ - max3107_handletx(s); - - /* Handle configuration changes */ - len = 0; - spin_lock_irqsave(&s->data_lock, flags); - if (s->mode1_commit) { - pr_debug("mode1_commit\n"); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - buf[len++] |= s->mode1_reg; - s->mode1_commit = 0; - } - if (s->lcr_commit) { - pr_debug("lcr_commit\n"); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG); - buf[len++] |= s->lcr_reg; - s->lcr_commit = 0; - } - if (s->brg_commit) { - pr_debug("brg_commit\n"); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG); - buf[len++] |= ((s->brg_cfg >> 16) & - MAX3107_SPI_TX_DATA_MASK); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG); - buf[len++] |= ((s->brg_cfg >> 8) & - MAX3107_SPI_TX_DATA_MASK); - buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG); - buf[len++] |= ((s->brg_cfg) & 0xff); - s->brg_commit = 0; - } - spin_unlock_irqrestore(&s->data_lock, flags); - - if (len > 0) { - if (max3107_rw(s, (u8 *)buf, NULL, len * 2)) - dev_err(&s->spi->dev, - "SPI transfer config failed\n"); - } - - /* Reloop if interrupt handling indicated data in RX FIFO */ - } while (rxlvl); - -} - -/* Set sleep mode */ -static void max3107_set_sleep(struct max3107_port *s, int mode) -{ - u16 buf[1]; /* Buffer for SPI transfer */ - unsigned long flags; - pr_debug("enter, mode %d\n", mode); - - buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG); - spin_lock_irqsave(&s->data_lock, flags); - switch (mode) { - case MAX3107_DISABLE_FORCED_SLEEP: - s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT; - break; - case MAX3107_ENABLE_FORCED_SLEEP: - s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT; - break; - case MAX3107_DISABLE_AUTOSLEEP: - s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT; - break; - case MAX3107_ENABLE_AUTOSLEEP: - s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT; - break; - default: - spin_unlock_irqrestore(&s->data_lock, flags); - dev_warn(&s->spi->dev, "invalid sleep mode\n"); - return; - } - buf[0] |= s->mode1_reg; - spin_unlock_irqrestore(&s->data_lock, flags); - - if (max3107_rw(s, (u8 *)buf, NULL, 2)) - dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n"); - - if (mode == MAX3107_DISABLE_AUTOSLEEP || - mode == MAX3107_DISABLE_FORCED_SLEEP) - msleep(MAX3107_WAKEUP_DELAY); -} - -/* Perform full register initialization */ -static void max3107_register_init(struct max3107_port *s) -{ - u16 buf[11]; /* Buffer for SPI transfers */ - - /* 1. Configure baud rate, 9600 as default */ - s->baud = 9600; - /* the below is default*/ - if (s->ext_clk) { - s->brg_cfg = MAX3107_BRG26_B9600; - s->baud_tbl = (struct baud_table *)brg26_ext; - } else { - s->brg_cfg = MAX3107_BRG13_IB9600; - s->baud_tbl = (struct baud_table *)brg13_int; - } - - if (s->pdata->init) - s->pdata->init(s); - - buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG) - | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK); - buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG) - | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK); - buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG) - | ((s->brg_cfg) & 0xff); - - /* 2. Configure LCR register, 8N1 mode by default */ - s->lcr_reg = MAX3107_LCR_WORD_LEN_8; - buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG) - | s->lcr_reg; - - /* 3. Configure MODE 1 register */ - s->mode1_reg = 0; - /* Enable IRQ pin */ - s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT; - /* Disable TX */ - s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT; - s->tx_enabled = 0; - /* RX is enabled */ - s->rx_enabled = 1; - buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG) - | s->mode1_reg; - - /* 4. Configure MODE 2 register */ - buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG); - if (s->loopback) { - /* Enable loopback */ - buf[5] |= MAX3107_MODE2_LOOPBACK_BIT; - } - /* Reset FIFOs */ - buf[5] |= MAX3107_MODE2_FIFORST_BIT; - s->tx_fifo_empty = 1; - - /* 5. Configure FIFO trigger level register */ - buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG); - /* RX FIFO trigger for 16 words, TX FIFO trigger not used */ - buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0)); - - /* 6. Configure flow control levels */ - buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG); - /* Flow control halt level 96, resume level 48 */ - buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96)); - - /* 7. Configure flow control */ - buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG); - /* Enable auto CTS and auto RTS flow control */ - buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT); - - /* 8. Configure RX timeout register */ - buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG); - /* Timeout after 48 character intervals */ - buf[9] |= 0x0030; - - /* 9. Configure LSR interrupt enable register */ - buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG); - /* Enable RX timeout interrupt */ - buf[10] |= MAX3107_LSR_RXTO_BIT; - - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, 22)) - dev_err(&s->spi->dev, "SPI transfer for init failed\n"); - - /* 10. Clear IRQ status register by reading it */ - buf[0] = MAX3107_IRQSTS_REG; - - /* 11. Configure interrupt enable register */ - /* Enable LSR interrupt */ - s->irqen_reg = MAX3107_IRQ_LSR_BIT; - /* Enable RX FIFO interrupt */ - s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT; - buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG) - | s->irqen_reg; - - /* 12. Clear FIFO reset that was set in step 6 */ - buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG); - if (s->loopback) { - /* Keep loopback enabled */ - buf[2] |= MAX3107_MODE2_LOOPBACK_BIT; - } - - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6)) - dev_err(&s->spi->dev, "SPI transfer for init failed\n"); - -} - -/* IRQ handler */ -static irqreturn_t max3107_irq(int irqno, void *dev_id) -{ - struct max3107_port *s = dev_id; - - if (irqno != s->spi->irq) { - /* Unexpected IRQ */ - return IRQ_NONE; - } - - /* Indicate irq */ - s->handle_irq = 1; - - /* Trigger work thread */ - max3107_dowork(s); - - return IRQ_HANDLED; -} - -/* HW suspension function - * - * Currently autosleep is used to decrease current consumption, alternative - * approach would be to set the chip to reset mode if UART is not being - * used but that would mess the GPIOs - * - */ -void max3107_hw_susp(struct max3107_port *s, int suspend) -{ - pr_debug("enter, suspend %d\n", suspend); - - if (suspend) { - /* Suspend requested, - * enable autosleep to decrease current consumption - */ - s->suspended = 1; - max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP); - } else { - /* Resume requested, - * disable autosleep - */ - s->suspended = 0; - max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP); - } -} -EXPORT_SYMBOL_GPL(max3107_hw_susp); - -/* Modem status IRQ enabling */ -static void max3107_enable_ms(struct uart_port *port) -{ - /* Modem status not supported */ -} - -/* Data send function */ -static void max3107_start_tx(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - /* Trigger work thread for sending data */ - max3107_dowork(s); -} - -/* Function for checking that there is no pending transfers */ -static unsigned int max3107_tx_empty(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - pr_debug("returning %d\n", - (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit))); - return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit); -} - -/* Function for stopping RX */ -static void max3107_stop_rx(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - unsigned long flags; - - /* Set RX disabled in MODE 1 register */ - spin_lock_irqsave(&s->data_lock, flags); - s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT; - s->mode1_commit = 1; - spin_unlock_irqrestore(&s->data_lock, flags); - /* Set RX disabled */ - s->rx_enabled = 0; - /* Trigger work thread for doing the actual configuration change */ - max3107_dowork(s); -} - -/* Function for returning control pin states */ -static unsigned int max3107_get_mctrl(struct uart_port *port) -{ - /* DCD and DSR are not wired and CTS/RTS is handled automatically - * so just indicate DSR and CAR asserted - */ - return TIOCM_DSR | TIOCM_CAR; -} - -/* Function for setting control pin states */ -static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* DCD and DSR are not wired and CTS/RTS is hadnled automatically - * so do nothing - */ -} - -/* Function for configuring UART parameters */ -static void max3107_set_termios(struct uart_port *port, - struct ktermios *termios, - struct ktermios *old) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - struct tty_struct *tty; - int baud; - u16 new_lcr = 0; - u32 new_brg = 0; - unsigned long flags; - - if (!port->state) - return; - - tty = port->state->port.tty; - if (!tty) - return; - - /* Get new LCR register values */ - /* Word size */ - if ((termios->c_cflag & CSIZE) == CS7) - new_lcr |= MAX3107_LCR_WORD_LEN_7; - else - new_lcr |= MAX3107_LCR_WORD_LEN_8; - - /* Parity */ - if (termios->c_cflag & PARENB) { - new_lcr |= MAX3107_LCR_PARITY_BIT; - if (!(termios->c_cflag & PARODD)) - new_lcr |= MAX3107_LCR_EVENPARITY_BIT; - } - - /* Stop bits */ - if (termios->c_cflag & CSTOPB) { - /* 2 stop bits */ - new_lcr |= MAX3107_LCR_STOPLEN_BIT; - } - - /* Mask termios capabilities we don't support */ - termios->c_cflag &= ~CMSPAR; - - /* Set status ignore mask */ - s->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - s->port.ignore_status_mask |= MAX3107_ALL_ERRORS; - - /* Set low latency to immediately handle pushed data */ - s->port.state->port.tty->low_latency = 1; - - /* Get new baud rate generator configuration */ - baud = tty_get_baud_rate(tty); - - spin_lock_irqsave(&s->data_lock, flags); - new_brg = get_new_brg(baud, s); - /* if can't find the corrent config, use previous */ - if (!new_brg) { - baud = s->baud; - new_brg = s->brg_cfg; - } - spin_unlock_irqrestore(&s->data_lock, flags); - tty_termios_encode_baud_rate(termios, baud, baud); - s->baud = baud; - - /* Update timeout according to new baud rate */ - uart_update_timeout(port, termios->c_cflag, baud); - - spin_lock_irqsave(&s->data_lock, flags); - if (s->lcr_reg != new_lcr) { - s->lcr_reg = new_lcr; - s->lcr_commit = 1; - } - if (s->brg_cfg != new_brg) { - s->brg_cfg = new_brg; - s->brg_commit = 1; - } - spin_unlock_irqrestore(&s->data_lock, flags); - - /* Trigger work thread for doing the actual configuration change */ - max3107_dowork(s); -} - -/* Port shutdown function */ -static void max3107_shutdown(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - if (s->suspended && s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 0); - - /* Free the interrupt */ - free_irq(s->spi->irq, s); - - if (s->workqueue) { - /* Flush and destroy work queue */ - flush_workqueue(s->workqueue); - destroy_workqueue(s->workqueue); - s->workqueue = NULL; - } - - /* Suspend HW */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 1); -} - -/* Port startup function */ -static int max3107_startup(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - - /* Initialize work queue */ - s->workqueue = create_freezable_workqueue("max3107"); - if (!s->workqueue) { - dev_err(&s->spi->dev, "Workqueue creation failed\n"); - return -EBUSY; - } - INIT_WORK(&s->work, max3107_work); - - /* Setup IRQ */ - if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING, - "max3107", s)) { - dev_err(&s->spi->dev, "IRQ reguest failed\n"); - destroy_workqueue(s->workqueue); - s->workqueue = NULL; - return -EBUSY; - } - - /* Resume HW */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 0); - - /* Init registers */ - max3107_register_init(s); - - return 0; -} - -/* Port type function */ -static const char *max3107_type(struct uart_port *port) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - return s->spi->modalias; -} - -/* Port release function */ -static void max3107_release_port(struct uart_port *port) -{ - /* Do nothing */ -} - -/* Port request function */ -static int max3107_request_port(struct uart_port *port) -{ - /* Do nothing */ - return 0; -} - -/* Port config function */ -static void max3107_config_port(struct uart_port *port, int flags) -{ - struct max3107_port *s = container_of(port, struct max3107_port, port); - s->port.type = PORT_MAX3107; -} - -/* Port verify function */ -static int max3107_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107) - return 0; - - return -EINVAL; -} - -/* Port stop TX function */ -static void max3107_stop_tx(struct uart_port *port) -{ - /* Do nothing */ -} - -/* Port break control function */ -static void max3107_break_ctl(struct uart_port *port, int break_state) -{ - /* We don't support break control, do nothing */ -} - - -/* Port functions */ -static struct uart_ops max3107_ops = { - .tx_empty = max3107_tx_empty, - .set_mctrl = max3107_set_mctrl, - .get_mctrl = max3107_get_mctrl, - .stop_tx = max3107_stop_tx, - .start_tx = max3107_start_tx, - .stop_rx = max3107_stop_rx, - .enable_ms = max3107_enable_ms, - .break_ctl = max3107_break_ctl, - .startup = max3107_startup, - .shutdown = max3107_shutdown, - .set_termios = max3107_set_termios, - .type = max3107_type, - .release_port = max3107_release_port, - .request_port = max3107_request_port, - .config_port = max3107_config_port, - .verify_port = max3107_verify_port, -}; - -/* UART driver data */ -static struct uart_driver max3107_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "ttyMAX", - .dev_name = "ttyMAX", - .nr = 1, -}; - -static int driver_registered = 0; - - - -/* 'Generic' platform data */ -static struct max3107_plat generic_plat_data = { - .loopback = 0, - .ext_clk = 1, - .hw_suspend = max3107_hw_susp, - .polled_mode = 0, - .poll_time = 0, -}; - - -/*******************************************************************/ - -/** - * max3107_probe - SPI bus probe entry point - * @spi: the spi device - * - * SPI wants us to probe this device and if appropriate claim it. - * Perform any platform specific requirements and then initialise - * the device. - */ - -int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata) -{ - struct max3107_port *s; - u16 buf[2]; /* Buffer for SPI transfers */ - int retval; - - pr_info("enter max3107 probe\n"); - - /* Allocate port structure */ - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) { - pr_err("Allocating port structure failed\n"); - return -ENOMEM; - } - - s->pdata = pdata; - - /* SPI Rx buffer - * +2 for RX FIFO interrupt - * disabling and RX level query - */ - s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL); - if (!s->rxbuf) { - pr_err("Allocating RX buffer failed\n"); - retval = -ENOMEM; - goto err_free4; - } - s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL); - if (!s->rxstr) { - pr_err("Allocating RX buffer failed\n"); - retval = -ENOMEM; - goto err_free3; - } - /* SPI Tx buffer - * SPI transfer buffer - * +3 for TX FIFO empty - * interrupt disabling and - * enabling and TX enabling - */ - s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL); - if (!s->txbuf) { - pr_err("Allocating TX buffer failed\n"); - retval = -ENOMEM; - goto err_free2; - } - /* Initialize shared data lock */ - spin_lock_init(&s->data_lock); - - /* SPI intializations */ - dev_set_drvdata(&spi->dev, s); - spi->mode = SPI_MODE_0; - spi->dev.platform_data = pdata; - spi->bits_per_word = 16; - s->ext_clk = pdata->ext_clk; - s->loopback = pdata->loopback; - spi_setup(spi); - s->spi = spi; - - /* Check REV ID to ensure we are talking to what we expect */ - buf[0] = MAX3107_REVID_REG; - if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) { - dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n"); - retval = -EIO; - goto err_free1; - } - if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 && - (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) { - dev_err(&s->spi->dev, "REVID %x does not match\n", - (buf[0] & MAX3107_SPI_RX_DATA_MASK)); - retval = -ENODEV; - goto err_free1; - } - - /* Disable all interrupts */ - buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000); - buf[0] |= 0x0000; - - /* Configure clock source */ - buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG); - if (s->ext_clk) { - /* External clock */ - buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT; - } - - /* PLL bypass ON */ - buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT; - - /* Perform SPI transfer */ - if (max3107_rw(s, (u8 *)buf, NULL, 4)) { - dev_err(&s->spi->dev, "SPI transfer for init failed\n"); - retval = -EIO; - goto err_free1; - } - - /* Register UART driver */ - if (!driver_registered) { - retval = uart_register_driver(&max3107_uart_driver); - if (retval) { - dev_err(&s->spi->dev, "Registering UART driver failed\n"); - goto err_free1; - } - driver_registered = 1; - } - - /* Initialize UART port data */ - s->port.fifosize = 128; - s->port.ops = &max3107_ops; - s->port.line = 0; - s->port.dev = &spi->dev; - s->port.uartclk = 9600; - s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; - s->port.irq = s->spi->irq; - s->port.type = PORT_MAX3107; - - /* Add UART port */ - retval = uart_add_one_port(&max3107_uart_driver, &s->port); - if (retval < 0) { - dev_err(&s->spi->dev, "Adding UART port failed\n"); - goto err_free1; - } - - if (pdata->configure) { - retval = pdata->configure(s); - if (retval < 0) - goto err_free1; - } - - /* Go to suspend mode */ - if (pdata->hw_suspend) - pdata->hw_suspend(s, 1); - - return 0; - -err_free1: - kfree(s->txbuf); -err_free2: - kfree(s->rxstr); -err_free3: - kfree(s->rxbuf); -err_free4: - kfree(s); - return retval; -} -EXPORT_SYMBOL_GPL(max3107_probe); - -/* Driver remove function */ -int max3107_remove(struct spi_device *spi) -{ - struct max3107_port *s = dev_get_drvdata(&spi->dev); - - pr_info("enter max3107 remove\n"); - - /* Remove port */ - if (uart_remove_one_port(&max3107_uart_driver, &s->port)) - dev_warn(&s->spi->dev, "Removing UART port failed\n"); - - - /* Free TxRx buffer */ - kfree(s->rxbuf); - kfree(s->rxstr); - kfree(s->txbuf); - - /* Free port structure */ - kfree(s); - - return 0; -} -EXPORT_SYMBOL_GPL(max3107_remove); - -/* Driver suspend function */ -int max3107_suspend(struct spi_device *spi, pm_message_t state) -{ -#ifdef CONFIG_PM - struct max3107_port *s = dev_get_drvdata(&spi->dev); - - pr_debug("enter suspend\n"); - - /* Suspend UART port */ - uart_suspend_port(&max3107_uart_driver, &s->port); - - /* Go to suspend mode */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 1); -#endif /* CONFIG_PM */ - return 0; -} -EXPORT_SYMBOL_GPL(max3107_suspend); - -/* Driver resume function */ -int max3107_resume(struct spi_device *spi) -{ -#ifdef CONFIG_PM - struct max3107_port *s = dev_get_drvdata(&spi->dev); - - pr_debug("enter resume\n"); - - /* Resume from suspend */ - if (s->pdata->hw_suspend) - s->pdata->hw_suspend(s, 0); - - /* Resume UART port */ - uart_resume_port(&max3107_uart_driver, &s->port); -#endif /* CONFIG_PM */ - return 0; -} -EXPORT_SYMBOL_GPL(max3107_resume); - -static int max3107_probe_generic(struct spi_device *spi) -{ - return max3107_probe(spi, &generic_plat_data); -} - -/* Spi driver data */ -static struct spi_driver max3107_driver = { - .driver = { - .name = "max3107", - .owner = THIS_MODULE, - }, - .probe = max3107_probe_generic, - .remove = __devexit_p(max3107_remove), - .suspend = max3107_suspend, - .resume = max3107_resume, -}; - -/* Driver init function */ -static int __init max3107_init(void) -{ - pr_info("enter max3107 init\n"); - return spi_register_driver(&max3107_driver); -} - -/* Driver exit function */ -static void __exit max3107_exit(void) -{ - pr_info("enter max3107 exit\n"); - /* Unregister UART driver */ - if (driver_registered) - uart_unregister_driver(&max3107_uart_driver); - spi_unregister_driver(&max3107_driver); -} - -module_init(max3107_init); -module_exit(max3107_exit); - -MODULE_DESCRIPTION("MAX3107 driver"); -MODULE_AUTHOR("Aavamobile"); -MODULE_ALIAS("spi:max3107"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h deleted file mode 100644 index 8415fc7..0000000 --- a/drivers/tty/serial/max3107.h +++ /dev/null @@ -1,441 +0,0 @@ -/* - * max3107.h - spi uart protocol driver header for Maxim 3107 - * - * Copyright (C) Aavamobile 2009 - * Based on serial_max3100.h by Christian Pellegrin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef _MAX3107_H -#define _MAX3107_H - -/* Serial error status definitions */ -#define MAX3107_PARITY_ERROR 1 -#define MAX3107_FRAME_ERROR 2 -#define MAX3107_OVERRUN_ERROR 4 -#define MAX3107_ALL_ERRORS (MAX3107_PARITY_ERROR | \ - MAX3107_FRAME_ERROR | \ - MAX3107_OVERRUN_ERROR) - -/* GPIO definitions */ -#define MAX3107_GPIO_BASE 88 -#define MAX3107_GPIO_COUNT 4 - - -/* GPIO connected to chip's reset pin */ -#define MAX3107_RESET_GPIO 87 - - -/* Chip reset delay */ -#define MAX3107_RESET_DELAY 10 - -/* Chip wakeup delay */ -#define MAX3107_WAKEUP_DELAY 50 - - -/* Sleep mode definitions */ -#define MAX3107_DISABLE_FORCED_SLEEP 0 -#define MAX3107_ENABLE_FORCED_SLEEP 1 -#define MAX3107_DISABLE_AUTOSLEEP 2 -#define MAX3107_ENABLE_AUTOSLEEP 3 - - -/* Definitions for register access with SPI transfers - * - * SPI transfer format: - * - * Master to slave bits xzzzzzzzyyyyyyyy - * Slave to master bits aaaaaaaabbbbbbbb - * - * where: - * x = 0 for reads, 1 for writes - * z = register address - * y = new register value if write, 0 if read - * a = unspecified - * b = register value if read, unspecified if write - */ - -/* SPI speed */ -#define MAX3107_SPI_SPEED (3125000 * 2) - -/* Write bit */ -#define MAX3107_WRITE_BIT (1 << 15) - -/* SPI TX data mask */ -#define MAX3107_SPI_RX_DATA_MASK (0x00ff) - -/* SPI RX data mask */ -#define MAX3107_SPI_TX_DATA_MASK (0x00ff) - -/* Register access masks */ -#define MAX3107_RHR_REG (0x0000) /* RX FIFO */ -#define MAX3107_THR_REG (0x0000) /* TX FIFO */ -#define MAX3107_IRQEN_REG (0x0100) /* IRQ enable */ -#define MAX3107_IRQSTS_REG (0x0200) /* IRQ status */ -#define MAX3107_LSR_IRQEN_REG (0x0300) /* LSR IRQ enable */ -#define MAX3107_LSR_IRQSTS_REG (0x0400) /* LSR IRQ status */ -#define MAX3107_SPCHR_IRQEN_REG (0x0500) /* Special char IRQ enable */ -#define MAX3107_SPCHR_IRQSTS_REG (0x0600) /* Special char IRQ status */ -#define MAX3107_STS_IRQEN_REG (0x0700) /* Status IRQ enable */ -#define MAX3107_STS_IRQSTS_REG (0x0800) /* Status IRQ status */ -#define MAX3107_MODE1_REG (0x0900) /* MODE1 */ -#define MAX3107_MODE2_REG (0x0a00) /* MODE2 */ -#define MAX3107_LCR_REG (0x0b00) /* LCR */ -#define MAX3107_RXTO_REG (0x0c00) /* RX timeout */ -#define MAX3107_HDPIXDELAY_REG (0x0d00) /* Auto transceiver delays */ -#define MAX3107_IRDA_REG (0x0e00) /* IRDA settings */ -#define MAX3107_FLOWLVL_REG (0x0f00) /* Flow control levels */ -#define MAX3107_FIFOTRIGLVL_REG (0x1000) /* FIFO IRQ trigger levels */ -#define MAX3107_TXFIFOLVL_REG (0x1100) /* TX FIFO level */ -#define MAX3107_RXFIFOLVL_REG (0x1200) /* RX FIFO level */ -#define MAX3107_FLOWCTRL_REG (0x1300) /* Flow control */ -#define MAX3107_XON1_REG (0x1400) /* XON1 character */ -#define MAX3107_XON2_REG (0x1500) /* XON2 character */ -#define MAX3107_XOFF1_REG (0x1600) /* XOFF1 character */ -#define MAX3107_XOFF2_REG (0x1700) /* XOFF2 character */ -#define MAX3107_GPIOCFG_REG (0x1800) /* GPIO config */ -#define MAX3107_GPIODATA_REG (0x1900) /* GPIO data */ -#define MAX3107_PLLCFG_REG (0x1a00) /* PLL config */ -#define MAX3107_BRGCFG_REG (0x1b00) /* Baud rate generator conf */ -#define MAX3107_BRGDIVLSB_REG (0x1c00) /* Baud rate divisor LSB */ -#define MAX3107_BRGDIVMSB_REG (0x1d00) /* Baud rate divisor MSB */ -#define MAX3107_CLKSRC_REG (0x1e00) /* Clock source */ -#define MAX3107_REVID_REG (0x1f00) /* Revision identification */ - -/* IRQ register bits */ -#define MAX3107_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ -#define MAX3107_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */ -#define MAX3107_IRQ_STS_BIT (1 << 2) /* Status interrupt */ -#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */ -#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */ -#define MAX3107_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */ -#define MAX3107_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */ -#define MAX3107_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */ - -/* LSR register bits */ -#define MAX3107_LSR_RXTO_BIT (1 << 0) /* RX timeout */ -#define MAX3107_LSR_RXOVR_BIT (1 << 1) /* RX overrun */ -#define MAX3107_LSR_RXPAR_BIT (1 << 2) /* RX parity error */ -#define MAX3107_LSR_FRERR_BIT (1 << 3) /* Frame error */ -#define MAX3107_LSR_RXBRK_BIT (1 << 4) /* RX break */ -#define MAX3107_LSR_RXNOISE_BIT (1 << 5) /* RX noise */ -#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_LSR_CTS_BIT (1 << 7) /* CTS pin state */ - -/* Special character register bits */ -#define MAX3107_SPCHR_XON1_BIT (1 << 0) /* XON1 character */ -#define MAX3107_SPCHR_XON2_BIT (1 << 1) /* XON2 character */ -#define MAX3107_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */ -#define MAX3107_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */ -#define MAX3107_SPCHR_BREAK_BIT (1 << 4) /* RX break */ -#define MAX3107_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */ -#define MAX3107_SPCHR_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_SPCHR_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* Status register bits */ -#define MAX3107_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */ -#define MAX3107_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */ -#define MAX3107_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */ -#define MAX3107_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */ -#define MAX3107_STS_UNDEF4_BIT (1 << 4) /* Undefined/not used */ -#define MAX3107_STS_CLKREADY_BIT (1 << 5) /* Clock ready */ -#define MAX3107_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */ -#define MAX3107_STS_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* MODE1 register bits */ -#define MAX3107_MODE1_RXDIS_BIT (1 << 0) /* RX disable */ -#define MAX3107_MODE1_TXDIS_BIT (1 << 1) /* TX disable */ -#define MAX3107_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */ -#define MAX3107_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */ -#define MAX3107_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */ -#define MAX3107_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */ -#define MAX3107_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */ -#define MAX3107_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */ - -/* MODE2 register bits */ -#define MAX3107_MODE2_RST_BIT (1 << 0) /* Chip reset */ -#define MAX3107_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */ -#define MAX3107_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */ -#define MAX3107_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */ -#define MAX3107_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */ -#define MAX3107_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */ -#define MAX3107_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */ -#define MAX3107_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */ - -/* LCR register bits */ -#define MAX3107_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */ -#define MAX3107_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1 - * - * Word length bits table: - * 00 -> 5 bit words - * 01 -> 6 bit words - * 10 -> 7 bit words - * 11 -> 8 bit words - */ -#define MAX3107_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit - * - * STOP length bit table: - * 0 -> 1 stop bit - * 1 -> 1-1.5 stop bits if - * word length is 5, - * 2 stop bits otherwise - */ -#define MAX3107_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */ -#define MAX3107_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */ -#define MAX3107_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ -#define MAX3107_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ -#define MAX3107_LCR_RTS_BIT (1 << 7) /* RTS pin control */ -#define MAX3107_LCR_WORD_LEN_5 (0x0000) -#define MAX3107_LCR_WORD_LEN_6 (0x0001) -#define MAX3107_LCR_WORD_LEN_7 (0x0002) -#define MAX3107_LCR_WORD_LEN_8 (0x0003) - - -/* IRDA register bits */ -#define MAX3107_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ -#define MAX3107_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ -#define MAX3107_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */ -#define MAX3107_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */ -#define MAX3107_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */ -#define MAX3107_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */ -#define MAX3107_IRDA_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_IRDA_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* Flow control trigger level register masks */ -#define MAX3107_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ -#define MAX3107_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */ -#define MAX3107_FLOWLVL_HALT(words) ((words/8) & 0x000f) -#define MAX3107_FLOWLVL_RES(words) (((words/8) & 0x000f) << 4) - -/* FIFO interrupt trigger level register masks */ -#define MAX3107_FIFOTRIGLVL_TX_MASK (0x000f) /* TX FIFO trigger level */ -#define MAX3107_FIFOTRIGLVL_RX_MASK (0x00f0) /* RX FIFO trigger level */ -#define MAX3107_FIFOTRIGLVL_TX(words) ((words/8) & 0x000f) -#define MAX3107_FIFOTRIGLVL_RX(words) (((words/8) & 0x000f) << 4) - -/* Flow control register bits */ -#define MAX3107_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */ -#define MAX3107_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */ -#define MAX3107_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs - * are used in conjunction with - * XOFF2 for definition of - * special character */ -#define MAX3107_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */ -#define MAX3107_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */ -#define MAX3107_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1 - * - * SWFLOW bits 1 & 0 table: - * 00 -> no transmitter flow - * control - * 01 -> receiver compares - * XON2 and XOFF2 - * and controls - * transmitter - * 10 -> receiver compares - * XON1 and XOFF1 - * and controls - * transmitter - * 11 -> receiver compares - * XON1, XON2, XOFF1 and - * XOFF2 and controls - * transmitter - */ -#define MAX3107_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */ -#define MAX3107_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3 - * - * SWFLOW bits 3 & 2 table: - * 00 -> no received flow - * control - * 01 -> transmitter generates - * XON2 and XOFF2 - * 10 -> transmitter generates - * XON1 and XOFF1 - * 11 -> transmitter generates - * XON1, XON2, XOFF1 and - * XOFF2 - */ - -/* GPIO configuration register bits */ -#define MAX3107_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */ -#define MAX3107_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */ -#define MAX3107_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */ -#define MAX3107_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */ -#define MAX3107_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */ -#define MAX3107_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */ -#define MAX3107_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */ -#define MAX3107_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */ - -/* GPIO DATA register bits */ -#define MAX3107_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */ -#define MAX3107_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */ -#define MAX3107_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */ -#define MAX3107_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */ -#define MAX3107_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */ -#define MAX3107_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */ -#define MAX3107_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */ -#define MAX3107_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */ - -/* PLL configuration register masks */ -#define MAX3107_PLLCFG_PREDIV_MASK (0x003f) /* PLL predivision value */ -#define MAX3107_PLLCFG_PLLFACTOR_MASK (0x00c0) /* PLL multiplication factor */ - -/* Baud rate generator configuration register masks and bits */ -#define MAX3107_BRGCFG_FRACT_MASK (0x000f) /* Fractional portion of - * Baud rate generator divisor - */ -#define MAX3107_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */ -#define MAX3107_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */ -#define MAX3107_BRGCFG_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_BRGCFG_UNDEF7_BIT (1 << 7) /* Undefined/not used */ - -/* Clock source register bits */ -#define MAX3107_CLKSRC_INTOSC_BIT (1 << 0) /* Internal osc enable */ -#define MAX3107_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */ -#define MAX3107_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */ -#define MAX3107_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */ -#define MAX3107_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */ -#define MAX3107_CLKSRC_UNDEF5_BIT (1 << 5) /* Undefined/not used */ -#define MAX3107_CLKSRC_UNDEF6_BIT (1 << 6) /* Undefined/not used */ -#define MAX3107_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */ - - -/* HW definitions */ -#define MAX3107_RX_FIFO_SIZE 128 -#define MAX3107_TX_FIFO_SIZE 128 -#define MAX3107_REVID1 0x00a0 -#define MAX3107_REVID2 0x00a1 - - -/* Baud rate generator configuration values for external clock 13MHz */ -#define MAX3107_BRG13_B300 (0x0A9400 | 0x05) -#define MAX3107_BRG13_B600 (0x054A00 | 0x03) -#define MAX3107_BRG13_B1200 (0x02A500 | 0x01) -#define MAX3107_BRG13_B2400 (0x015200 | 0x09) -#define MAX3107_BRG13_B4800 (0x00A900 | 0x04) -#define MAX3107_BRG13_B9600 (0x005400 | 0x0A) -#define MAX3107_BRG13_B19200 (0x002A00 | 0x05) -#define MAX3107_BRG13_B38400 (0x001500 | 0x03) -#define MAX3107_BRG13_B57600 (0x000E00 | 0x02) -#define MAX3107_BRG13_B115200 (0x000700 | 0x01) -#define MAX3107_BRG13_B230400 (0x000300 | 0x08) -#define MAX3107_BRG13_B460800 (0x000100 | 0x0c) -#define MAX3107_BRG13_B921600 (0x000100 | 0x1c) - -/* Baud rate generator configuration values for external clock 26MHz */ -#define MAX3107_BRG26_B300 (0x152800 | 0x0A) -#define MAX3107_BRG26_B600 (0x0A9400 | 0x05) -#define MAX3107_BRG26_B1200 (0x054A00 | 0x03) -#define MAX3107_BRG26_B2400 (0x02A500 | 0x01) -#define MAX3107_BRG26_B4800 (0x015200 | 0x09) -#define MAX3107_BRG26_B9600 (0x00A900 | 0x04) -#define MAX3107_BRG26_B19200 (0x005400 | 0x0A) -#define MAX3107_BRG26_B38400 (0x002A00 | 0x05) -#define MAX3107_BRG26_B57600 (0x001C00 | 0x03) -#define MAX3107_BRG26_B115200 (0x000E00 | 0x02) -#define MAX3107_BRG26_B230400 (0x000700 | 0x01) -#define MAX3107_BRG26_B460800 (0x000300 | 0x08) -#define MAX3107_BRG26_B921600 (0x000100 | 0x0C) - -/* Baud rate generator configuration values for internal clock */ -#define MAX3107_BRG13_IB300 (0x008000 | 0x00) -#define MAX3107_BRG13_IB600 (0x004000 | 0x00) -#define MAX3107_BRG13_IB1200 (0x002000 | 0x00) -#define MAX3107_BRG13_IB2400 (0x001000 | 0x00) -#define MAX3107_BRG13_IB4800 (0x000800 | 0x00) -#define MAX3107_BRG13_IB9600 (0x000400 | 0x00) -#define MAX3107_BRG13_IB19200 (0x000200 | 0x00) -#define MAX3107_BRG13_IB38400 (0x000100 | 0x00) -#define MAX3107_BRG13_IB57600 (0x000000 | 0x0B) -#define MAX3107_BRG13_IB115200 (0x000000 | 0x05) -#define MAX3107_BRG13_IB230400 (0x000000 | 0x03) -#define MAX3107_BRG13_IB460800 (0x000000 | 0x00) -#define MAX3107_BRG13_IB921600 (0x000000 | 0x00) - - -struct baud_table { - int baud; - u32 new_brg; -}; - -struct max3107_port { - /* UART port structure */ - struct uart_port port; - - /* SPI device structure */ - struct spi_device *spi; - -#if defined(CONFIG_GPIOLIB) - /* GPIO chip structure */ - struct gpio_chip chip; -#endif - - /* Workqueue that does all the magic */ - struct workqueue_struct *workqueue; - struct work_struct work; - - /* Lock for shared data */ - spinlock_t data_lock; - - /* Device configuration */ - int ext_clk; /* 1 if external clock used */ - int loopback; /* Current loopback mode state */ - int baud; /* Current baud rate */ - - /* State flags */ - int suspended; /* Indicates suspend mode */ - int tx_fifo_empty; /* Flag for TX FIFO state */ - int rx_enabled; /* Flag for receiver state */ - int tx_enabled; /* Flag for transmitter state */ - - u16 irqen_reg; /* Current IRQ enable register value */ - /* Shared data */ - u16 mode1_reg; /* Current mode1 register value*/ - int mode1_commit; /* Flag for setting new mode1 register value */ - u16 lcr_reg; /* Current LCR register value */ - int lcr_commit; /* Flag for setting new LCR register value */ - u32 brg_cfg; /* Current Baud rate generator config */ - int brg_commit; /* Flag for setting new baud rate generator - * config - */ - struct baud_table *baud_tbl; - int handle_irq; /* Indicates that IRQ should be handled */ - - /* Rx buffer and str*/ - u16 *rxbuf; - u8 *rxstr; - /* Tx buffer*/ - u16 *txbuf; - - struct max3107_plat *pdata; /* Platform data */ -}; - -/* Platform data structure */ -struct max3107_plat { - /* Loopback mode enable */ - int loopback; - /* External clock enable */ - int ext_clk; - /* Called during the register initialisation */ - void (*init)(struct max3107_port *s); - /* Called when the port is found and configured */ - int (*configure)(struct max3107_port *s); - /* HW suspend function */ - void (*hw_suspend) (struct max3107_port *s, int suspend); - /* Polling mode enable */ - int polled_mode; - /* Polling period if polling mode enabled */ - int poll_time; -}; - -extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len); -extern void max3107_hw_susp(struct max3107_port *s, int suspend); -extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata); -extern int max3107_remove(struct spi_device *spi); -extern int max3107_suspend(struct spi_device *spi, pm_message_t state); -extern int max3107_resume(struct spi_device *spi); - -#endif /* _LINUX_SERIAL_MAX3107_H */ diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c new file mode 100644 index 0000000..534e448 --- /dev/null +++ b/drivers/tty/serial/max310x.c @@ -0,0 +1,1259 @@ +/* + * Maxim (Dallas) MAX3107/8 serial driver + * + * Copyright (C) 2012 Alexander Shiyan + * + * Based on max3100.c, by Christian Pellegrin + * Based on max3110.c, by Feng Tang + * Based on max3107.c, by Aavamobile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* TODO: MAX3109 support (Dual) */ +/* TODO: MAX14830 support (Quad) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX310X_MAJOR 204 +#define MAX310X_MINOR 209 + +/* MAX310X register definitions */ +#define MAX310X_RHR_REG (0x00) /* RX FIFO */ +#define MAX310X_THR_REG (0x00) /* TX FIFO */ +#define MAX310X_IRQEN_REG (0x01) /* IRQ enable */ +#define MAX310X_IRQSTS_REG (0x02) /* IRQ status */ +#define MAX310X_LSR_IRQEN_REG (0x03) /* LSR IRQ enable */ +#define MAX310X_LSR_IRQSTS_REG (0x04) /* LSR IRQ status */ +#define MAX310X_SPCHR_IRQEN_REG (0x05) /* Special char IRQ enable */ +#define MAX310X_SPCHR_IRQSTS_REG (0x06) /* Special char IRQ status */ +#define MAX310X_STS_IRQEN_REG (0x07) /* Status IRQ enable */ +#define MAX310X_STS_IRQSTS_REG (0x08) /* Status IRQ status */ +#define MAX310X_MODE1_REG (0x09) /* MODE1 */ +#define MAX310X_MODE2_REG (0x0a) /* MODE2 */ +#define MAX310X_LCR_REG (0x0b) /* LCR */ +#define MAX310X_RXTO_REG (0x0c) /* RX timeout */ +#define MAX310X_HDPIXDELAY_REG (0x0d) /* Auto transceiver delays */ +#define MAX310X_IRDA_REG (0x0e) /* IRDA settings */ +#define MAX310X_FLOWLVL_REG (0x0f) /* Flow control levels */ +#define MAX310X_FIFOTRIGLVL_REG (0x10) /* FIFO IRQ trigger levels */ +#define MAX310X_TXFIFOLVL_REG (0x11) /* TX FIFO level */ +#define MAX310X_RXFIFOLVL_REG (0x12) /* RX FIFO level */ +#define MAX310X_FLOWCTRL_REG (0x13) /* Flow control */ +#define MAX310X_XON1_REG (0x14) /* XON1 character */ +#define MAX310X_XON2_REG (0x15) /* XON2 character */ +#define MAX310X_XOFF1_REG (0x16) /* XOFF1 character */ +#define MAX310X_XOFF2_REG (0x17) /* XOFF2 character */ +#define MAX310X_GPIOCFG_REG (0x18) /* GPIO config */ +#define MAX310X_GPIODATA_REG (0x19) /* GPIO data */ +#define MAX310X_PLLCFG_REG (0x1a) /* PLL config */ +#define MAX310X_BRGCFG_REG (0x1b) /* Baud rate generator conf */ +#define MAX310X_BRGDIVLSB_REG (0x1c) /* Baud rate divisor LSB */ +#define MAX310X_BRGDIVMSB_REG (0x1d) /* Baud rate divisor MSB */ +#define MAX310X_CLKSRC_REG (0x1e) /* Clock source */ +/* Only present in MAX3107 */ +#define MAX3107_REVID_REG (0x1f) /* Revision identification */ + +/* IRQ register bits */ +#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */ +#define MAX310X_IRQ_SPCHR_BIT (1 << 1) /* Special char interrupt */ +#define MAX310X_IRQ_STS_BIT (1 << 2) /* Status interrupt */ +#define MAX310X_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */ +#define MAX310X_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */ +#define MAX310X_IRQ_TXEMPTY_BIT (1 << 5) /* TX FIFO empty interrupt */ +#define MAX310X_IRQ_RXEMPTY_BIT (1 << 6) /* RX FIFO empty interrupt */ +#define MAX310X_IRQ_CTS_BIT (1 << 7) /* CTS interrupt */ + +/* LSR register bits */ +#define MAX310X_LSR_RXTO_BIT (1 << 0) /* RX timeout */ +#define MAX310X_LSR_RXOVR_BIT (1 << 1) /* RX overrun */ +#define MAX310X_LSR_RXPAR_BIT (1 << 2) /* RX parity error */ +#define MAX310X_LSR_FRERR_BIT (1 << 3) /* Frame error */ +#define MAX310X_LSR_RXBRK_BIT (1 << 4) /* RX break */ +#define MAX310X_LSR_RXNOISE_BIT (1 << 5) /* RX noise */ +#define MAX310X_LSR_CTS_BIT (1 << 7) /* CTS pin state */ + +/* Special character register bits */ +#define MAX310X_SPCHR_XON1_BIT (1 << 0) /* XON1 character */ +#define MAX310X_SPCHR_XON2_BIT (1 << 1) /* XON2 character */ +#define MAX310X_SPCHR_XOFF1_BIT (1 << 2) /* XOFF1 character */ +#define MAX310X_SPCHR_XOFF2_BIT (1 << 3) /* XOFF2 character */ +#define MAX310X_SPCHR_BREAK_BIT (1 << 4) /* RX break */ +#define MAX310X_SPCHR_MULTIDROP_BIT (1 << 5) /* 9-bit multidrop addr char */ + +/* Status register bits */ +#define MAX310X_STS_GPIO0_BIT (1 << 0) /* GPIO 0 interrupt */ +#define MAX310X_STS_GPIO1_BIT (1 << 1) /* GPIO 1 interrupt */ +#define MAX310X_STS_GPIO2_BIT (1 << 2) /* GPIO 2 interrupt */ +#define MAX310X_STS_GPIO3_BIT (1 << 3) /* GPIO 3 interrupt */ +#define MAX310X_STS_CLKREADY_BIT (1 << 5) /* Clock ready */ +#define MAX310X_STS_SLEEP_BIT (1 << 6) /* Sleep interrupt */ + +/* MODE1 register bits */ +#define MAX310X_MODE1_RXDIS_BIT (1 << 0) /* RX disable */ +#define MAX310X_MODE1_TXDIS_BIT (1 << 1) /* TX disable */ +#define MAX310X_MODE1_TXHIZ_BIT (1 << 2) /* TX pin three-state */ +#define MAX310X_MODE1_RTSHIZ_BIT (1 << 3) /* RTS pin three-state */ +#define MAX310X_MODE1_TRNSCVCTRL_BIT (1 << 4) /* Transceiver ctrl enable */ +#define MAX310X_MODE1_FORCESLEEP_BIT (1 << 5) /* Force sleep mode */ +#define MAX310X_MODE1_AUTOSLEEP_BIT (1 << 6) /* Auto sleep enable */ +#define MAX310X_MODE1_IRQSEL_BIT (1 << 7) /* IRQ pin enable */ + +/* MODE2 register bits */ +#define MAX310X_MODE2_RST_BIT (1 << 0) /* Chip reset */ +#define MAX310X_MODE2_FIFORST_BIT (1 << 1) /* FIFO reset */ +#define MAX310X_MODE2_RXTRIGINV_BIT (1 << 2) /* RX FIFO INT invert */ +#define MAX310X_MODE2_RXEMPTINV_BIT (1 << 3) /* RX FIFO empty INT invert */ +#define MAX310X_MODE2_SPCHR_BIT (1 << 4) /* Special chr detect enable */ +#define MAX310X_MODE2_LOOPBACK_BIT (1 << 5) /* Internal loopback enable */ +#define MAX310X_MODE2_MULTIDROP_BIT (1 << 6) /* 9-bit multidrop enable */ +#define MAX310X_MODE2_ECHOSUPR_BIT (1 << 7) /* ECHO suppression enable */ + +/* LCR register bits */ +#define MAX310X_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */ +#define MAX310X_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1 + * + * Word length bits table: + * 00 -> 5 bit words + * 01 -> 6 bit words + * 10 -> 7 bit words + * 11 -> 8 bit words + */ +#define MAX310X_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit + * + * STOP length bit table: + * 0 -> 1 stop bit + * 1 -> 1-1.5 stop bits if + * word length is 5, + * 2 stop bits otherwise + */ +#define MAX310X_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */ +#define MAX310X_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */ +#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ +#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ +#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */ +#define MAX310X_LCR_WORD_LEN_5 (0x00) +#define MAX310X_LCR_WORD_LEN_6 (0x01) +#define MAX310X_LCR_WORD_LEN_7 (0x02) +#define MAX310X_LCR_WORD_LEN_8 (0x03) + +/* IRDA register bits */ +#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ +#define MAX310X_IRDA_SIR_BIT (1 << 1) /* SIR mode enable */ +#define MAX310X_IRDA_SHORTIR_BIT (1 << 2) /* Short SIR mode enable */ +#define MAX310X_IRDA_MIR_BIT (1 << 3) /* MIR mode enable */ +#define MAX310X_IRDA_RXINV_BIT (1 << 4) /* RX logic inversion enable */ +#define MAX310X_IRDA_TXINV_BIT (1 << 5) /* TX logic inversion enable */ + +/* Flow control trigger level register masks */ +#define MAX310X_FLOWLVL_HALT_MASK (0x000f) /* Flow control halt level */ +#define MAX310X_FLOWLVL_RES_MASK (0x00f0) /* Flow control resume level */ +#define MAX310X_FLOWLVL_HALT(words) ((words / 8) & 0x0f) +#define MAX310X_FLOWLVL_RES(words) (((words / 8) & 0x0f) << 4) + +/* FIFO interrupt trigger level register masks */ +#define MAX310X_FIFOTRIGLVL_TX_MASK (0x0f) /* TX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_RX_MASK (0xf0) /* RX FIFO trigger level */ +#define MAX310X_FIFOTRIGLVL_TX(words) ((words / 8) & 0x0f) +#define MAX310X_FIFOTRIGLVL_RX(words) (((words / 8) & 0x0f) << 4) + +/* Flow control register bits */ +#define MAX310X_FLOWCTRL_AUTORTS_BIT (1 << 0) /* Auto RTS flow ctrl enable */ +#define MAX310X_FLOWCTRL_AUTOCTS_BIT (1 << 1) /* Auto CTS flow ctrl enable */ +#define MAX310X_FLOWCTRL_GPIADDR_BIT (1 << 2) /* Enables that GPIO inputs + * are used in conjunction with + * XOFF2 for definition of + * special character */ +#define MAX310X_FLOWCTRL_SWFLOWEN_BIT (1 << 3) /* Auto SW flow ctrl enable */ +#define MAX310X_FLOWCTRL_SWFLOW0_BIT (1 << 4) /* SWFLOW bit 0 */ +#define MAX310X_FLOWCTRL_SWFLOW1_BIT (1 << 5) /* SWFLOW bit 1 + * + * SWFLOW bits 1 & 0 table: + * 00 -> no transmitter flow + * control + * 01 -> receiver compares + * XON2 and XOFF2 + * and controls + * transmitter + * 10 -> receiver compares + * XON1 and XOFF1 + * and controls + * transmitter + * 11 -> receiver compares + * XON1, XON2, XOFF1 and + * XOFF2 and controls + * transmitter + */ +#define MAX310X_FLOWCTRL_SWFLOW2_BIT (1 << 6) /* SWFLOW bit 2 */ +#define MAX310X_FLOWCTRL_SWFLOW3_BIT (1 << 7) /* SWFLOW bit 3 + * + * SWFLOW bits 3 & 2 table: + * 00 -> no received flow + * control + * 01 -> transmitter generates + * XON2 and XOFF2 + * 10 -> transmitter generates + * XON1 and XOFF1 + * 11 -> transmitter generates + * XON1, XON2, XOFF1 and + * XOFF2 + */ + +/* GPIO configuration register bits */ +#define MAX310X_GPIOCFG_GP0OUT_BIT (1 << 0) /* GPIO 0 output enable */ +#define MAX310X_GPIOCFG_GP1OUT_BIT (1 << 1) /* GPIO 1 output enable */ +#define MAX310X_GPIOCFG_GP2OUT_BIT (1 << 2) /* GPIO 2 output enable */ +#define MAX310X_GPIOCFG_GP3OUT_BIT (1 << 3) /* GPIO 3 output enable */ +#define MAX310X_GPIOCFG_GP0OD_BIT (1 << 4) /* GPIO 0 open-drain enable */ +#define MAX310X_GPIOCFG_GP1OD_BIT (1 << 5) /* GPIO 1 open-drain enable */ +#define MAX310X_GPIOCFG_GP2OD_BIT (1 << 6) /* GPIO 2 open-drain enable */ +#define MAX310X_GPIOCFG_GP3OD_BIT (1 << 7) /* GPIO 3 open-drain enable */ + +/* GPIO DATA register bits */ +#define MAX310X_GPIODATA_GP0OUT_BIT (1 << 0) /* GPIO 0 output value */ +#define MAX310X_GPIODATA_GP1OUT_BIT (1 << 1) /* GPIO 1 output value */ +#define MAX310X_GPIODATA_GP2OUT_BIT (1 << 2) /* GPIO 2 output value */ +#define MAX310X_GPIODATA_GP3OUT_BIT (1 << 3) /* GPIO 3 output value */ +#define MAX310X_GPIODATA_GP0IN_BIT (1 << 4) /* GPIO 0 input value */ +#define MAX310X_GPIODATA_GP1IN_BIT (1 << 5) /* GPIO 1 input value */ +#define MAX310X_GPIODATA_GP2IN_BIT (1 << 6) /* GPIO 2 input value */ +#define MAX310X_GPIODATA_GP3IN_BIT (1 << 7) /* GPIO 3 input value */ + +/* PLL configuration register masks */ +#define MAX310X_PLLCFG_PREDIV_MASK (0x3f) /* PLL predivision value */ +#define MAX310X_PLLCFG_PLLFACTOR_MASK (0xc0) /* PLL multiplication factor */ + +/* Baud rate generator configuration register bits */ +#define MAX310X_BRGCFG_2XMODE_BIT (1 << 4) /* Double baud rate */ +#define MAX310X_BRGCFG_4XMODE_BIT (1 << 5) /* Quadruple baud rate */ + +/* Clock source register bits */ +#define MAX310X_CLKSRC_CRYST_BIT (1 << 1) /* Crystal osc enable */ +#define MAX310X_CLKSRC_PLL_BIT (1 << 2) /* PLL enable */ +#define MAX310X_CLKSRC_PLLBYP_BIT (1 << 3) /* PLL bypass */ +#define MAX310X_CLKSRC_EXTCLK_BIT (1 << 4) /* External clock enable */ +#define MAX310X_CLKSRC_CLK2RTS_BIT (1 << 7) /* Baud clk to RTS pin */ + +/* Misc definitions */ +#define MAX310X_FIFO_SIZE (128) + +/* MAX3107 specific */ +#define MAX3107_REV_ID (0xa0) +#define MAX3107_REV_MASK (0xfe) + +/* IRQ status bits definitions */ +#define MAX310X_IRQ_TX (MAX310X_IRQ_TXFIFO_BIT | \ + MAX310X_IRQ_TXEMPTY_BIT) +#define MAX310X_IRQ_RX (MAX310X_IRQ_RXFIFO_BIT | \ + MAX310X_IRQ_RXEMPTY_BIT) + +/* Supported chip types */ +enum { + MAX310X_TYPE_MAX3107 = 3107, + MAX310X_TYPE_MAX3108 = 3108, +}; + +struct max310x_port { + struct uart_driver uart; + struct uart_port port; + + const char *name; + int uartclk; + + unsigned int nr_gpio; +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio; +#endif + + struct regmap *regmap; + struct regmap_config regcfg; + + struct workqueue_struct *wq; + struct work_struct tx_work; + + struct mutex max310x_mutex; + + struct max310x_pdata *pdata; +}; + +static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX310X_IRQSTS_REG: + case MAX310X_LSR_IRQSTS_REG: + case MAX310X_SPCHR_IRQSTS_REG: + case MAX310X_STS_IRQSTS_REG: + case MAX310X_TXFIFOLVL_REG: + case MAX310X_RXFIFOLVL_REG: + case MAX3107_REVID_REG: /* Only available on MAX3107 */ + return false; + default: + break; + } + + return true; +} + +static bool max310x_reg_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX310X_RHR_REG: + case MAX310X_IRQSTS_REG: + case MAX310X_LSR_IRQSTS_REG: + case MAX310X_SPCHR_IRQSTS_REG: + case MAX310X_STS_IRQSTS_REG: + case MAX310X_TXFIFOLVL_REG: + case MAX310X_RXFIFOLVL_REG: + case MAX310X_GPIODATA_REG: + return true; + default: + break; + } + + return false; +} + +static bool max310x_reg_precious(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX310X_RHR_REG: + case MAX310X_IRQSTS_REG: + case MAX310X_SPCHR_IRQSTS_REG: + case MAX310X_STS_IRQSTS_REG: + return true; + default: + break; + } + + return false; +} + +static void max310x_set_baud(struct max310x_port *s, int baud) +{ + unsigned int mode = 0, div = s->uartclk / baud; + + if (!(div / 16)) { + /* Mode x2 */ + mode = MAX310X_BRGCFG_2XMODE_BIT; + div = (s->uartclk * 2) / baud; + } + + if (!(div / 16)) { + /* Mode x4 */ + mode = MAX310X_BRGCFG_4XMODE_BIT; + div = (s->uartclk * 4) / baud; + } + + regmap_write(s->regmap, MAX310X_BRGDIVMSB_REG, + ((div / 16) >> 8) & 0xff); + regmap_write(s->regmap, MAX310X_BRGDIVLSB_REG, (div / 16) & 0xff); + regmap_write(s->regmap, MAX310X_BRGCFG_REG, (div % 16) | mode); +} + +static void max310x_wait_pll(struct max310x_port *s) +{ + int tryes = 1000; + + /* Wait for PLL only if crystal is used */ + if (!(s->pdata->driver_flags & MAX310X_EXT_CLK)) { + unsigned int sts = 0; + + while (tryes--) { + regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &sts); + if (sts & MAX310X_STS_CLKREADY_BIT) + break; + } + } +} + +static int __devinit max310x_update_best_err(unsigned long f, long *besterr) +{ + /* Use baudrate 115200 for calculate error */ + long err = f % (115200 * 16); + + if ((*besterr < 0) || (*besterr > err)) { + *besterr = err; + return 0; + } + + return 1; +} + +static int __devinit max310x_set_ref_clk(struct max310x_port *s) +{ + unsigned int div, clksrc, pllcfg = 0; + long besterr = -1; + unsigned long fdiv, fmul, bestfreq = s->pdata->frequency; + + /* First, update error without PLL */ + max310x_update_best_err(s->pdata->frequency, &besterr); + + /* Try all possible PLL dividers */ + for (div = 1; (div <= 63) && besterr; div++) { + fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div); + + /* Try multiplier 6 */ + fmul = fdiv * 6; + if ((fdiv >= 500000) && (fdiv <= 800000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (0 << 6) | div; + bestfreq = fmul; + } + /* Try multiplier 48 */ + fmul = fdiv * 48; + if ((fdiv >= 850000) && (fdiv <= 1200000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (1 << 6) | div; + bestfreq = fmul; + } + /* Try multiplier 96 */ + fmul = fdiv * 96; + if ((fdiv >= 425000) && (fdiv <= 1000000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (2 << 6) | div; + bestfreq = fmul; + } + /* Try multiplier 144 */ + fmul = fdiv * 144; + if ((fdiv >= 390000) && (fdiv <= 667000)) + if (!max310x_update_best_err(fmul, &besterr)) { + pllcfg = (3 << 6) | div; + bestfreq = fmul; + } + } + + /* Configure clock source */ + if (s->pdata->driver_flags & MAX310X_EXT_CLK) + clksrc = MAX310X_CLKSRC_EXTCLK_BIT; + else + clksrc = MAX310X_CLKSRC_CRYST_BIT; + + /* Configure PLL */ + if (pllcfg) { + clksrc |= MAX310X_CLKSRC_PLL_BIT; + regmap_write(s->regmap, MAX310X_PLLCFG_REG, pllcfg); + } else + clksrc |= MAX310X_CLKSRC_PLLBYP_BIT; + + regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc); + + if (pllcfg) + max310x_wait_pll(s); + + dev_dbg(s->port.dev, "Reference clock set to %lu Hz\n", bestfreq); + + return (int)bestfreq; +} + +static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen) +{ + unsigned int sts = 0, ch = 0, flag; + struct tty_struct *tty = tty_port_tty_get(&s->port.state->port); + + if (!tty) + return; + + if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) { + dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen); + /* Ensure sanity of RX level */ + rxlen = MAX310X_FIFO_SIZE; + } + + dev_dbg(s->port.dev, "RX Len = %u\n", rxlen); + + while (rxlen--) { + regmap_read(s->regmap, MAX310X_RHR_REG, &ch); + regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts); + + sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT | + MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT; + + s->port.icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(sts)) { + if (sts & MAX310X_LSR_RXBRK_BIT) { + s->port.icount.brk++; + if (uart_handle_break(&s->port)) + continue; + } else if (sts & MAX310X_LSR_RXPAR_BIT) + s->port.icount.parity++; + else if (sts & MAX310X_LSR_FRERR_BIT) + s->port.icount.frame++; + else if (sts & MAX310X_LSR_RXOVR_BIT) + s->port.icount.overrun++; + + sts &= s->port.read_status_mask; + if (sts & MAX310X_LSR_RXBRK_BIT) + flag = TTY_BREAK; + else if (sts & MAX310X_LSR_RXPAR_BIT) + flag = TTY_PARITY; + else if (sts & MAX310X_LSR_FRERR_BIT) + flag = TTY_FRAME; + else if (sts & MAX310X_LSR_RXOVR_BIT) + flag = TTY_OVERRUN; + } + + if (uart_handle_sysrq_char(s->port, ch)) + continue; + + if (sts & s->port.ignore_status_mask) + continue; + + uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT, + ch, flag); + } + + tty_flip_buffer_push(tty); + + tty_kref_put(tty); +} + +static void max310x_handle_tx(struct max310x_port *s) +{ + struct circ_buf *xmit = &s->port.state->xmit; + unsigned int txlen = 0, to_send; + + if (unlikely(s->port.x_char)) { + regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char); + s->port.icount.tx++; + s->port.x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port)) + return; + + /* Get length of data pending in circular buffer */ + to_send = uart_circ_chars_pending(xmit); + if (likely(to_send)) { + /* Limit to size of TX FIFO */ + regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &txlen); + txlen = MAX310X_FIFO_SIZE - txlen; + to_send = (to_send > txlen) ? txlen : to_send; + + dev_dbg(s->port.dev, "TX Len = %u\n", to_send); + + /* Add data to send */ + s->port.icount.tx += to_send; + while (to_send--) { + regmap_write(s->regmap, MAX310X_THR_REG, + xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + }; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&s->port); +} + +static irqreturn_t max310x_ist(int irq, void *dev_id) +{ + struct max310x_port *s = (struct max310x_port *)dev_id; + unsigned int ists = 0, lsr = 0, rxlen = 0; + + mutex_lock(&s->max310x_mutex); + + for (;;) { + /* Read IRQ status & RX FIFO level */ + regmap_read(s->regmap, MAX310X_IRQSTS_REG, &ists); + regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &lsr); + regmap_read(s->regmap, MAX310X_RXFIFOLVL_REG, &rxlen); + if (!ists && !(lsr & MAX310X_LSR_RXTO_BIT) && !rxlen) + break; + + dev_dbg(s->port.dev, "IRQ status: 0x%02x\n", ists); + + if (rxlen) + max310x_handle_rx(s, rxlen); + if (ists & MAX310X_IRQ_TX) + max310x_handle_tx(s); + if (ists & MAX310X_IRQ_CTS_BIT) + uart_handle_cts_change(&s->port, + !!(lsr & MAX310X_LSR_CTS_BIT)); + } + + mutex_unlock(&s->max310x_mutex); + + return IRQ_HANDLED; +} + +static void max310x_wq_proc(struct work_struct *ws) +{ + struct max310x_port *s = container_of(ws, struct max310x_port, tx_work); + + mutex_lock(&s->max310x_mutex); + max310x_handle_tx(s); + mutex_unlock(&s->max310x_mutex); +} + +static void max310x_start_tx(struct uart_port *port) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + queue_work(s->wq, &s->tx_work); +} + +static void max310x_stop_tx(struct uart_port *port) +{ + /* Do nothing */ +} + +static void max310x_stop_rx(struct uart_port *port) +{ + /* Do nothing */ +} + +static unsigned int max310x_tx_empty(struct uart_port *port) +{ + unsigned int val = 0; + struct max310x_port *s = container_of(port, struct max310x_port, port); + + mutex_lock(&s->max310x_mutex); + regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &val); + mutex_unlock(&s->max310x_mutex); + + return val ? 0 : TIOCSER_TEMT; +} + +static void max310x_enable_ms(struct uart_port *port) +{ + /* Modem status not supported */ +} + +static unsigned int max310x_get_mctrl(struct uart_port *port) +{ + /* DCD and DSR are not wired and CTS/RTS is handled automatically + * so just indicate DSR and CAR asserted + */ + return TIOCM_DSR | TIOCM_CAR; +} + +static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* DCD and DSR are not wired and CTS/RTS is hadnled automatically + * so do nothing + */ +} + +static void max310x_break_ctl(struct uart_port *port, int break_state) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + mutex_lock(&s->max310x_mutex); + regmap_update_bits(s->regmap, MAX310X_LCR_REG, + MAX310X_LCR_TXBREAK_BIT, + break_state ? MAX310X_LCR_TXBREAK_BIT : 0); + mutex_unlock(&s->max310x_mutex); +} + +static void max310x_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + unsigned int lcr, flow = 0; + int baud; + + mutex_lock(&s->max310x_mutex); + + /* Mask termios capabilities we don't support */ + termios->c_cflag &= ~CMSPAR; + termios->c_iflag &= ~IXANY; + + /* Word size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + lcr = MAX310X_LCR_WORD_LEN_5; + break; + case CS6: + lcr = MAX310X_LCR_WORD_LEN_6; + break; + case CS7: + lcr = MAX310X_LCR_WORD_LEN_7; + break; + case CS8: + default: + lcr = MAX310X_LCR_WORD_LEN_8; + break; + } + + /* Parity */ + if (termios->c_cflag & PARENB) { + lcr |= MAX310X_LCR_PARITY_BIT; + if (!(termios->c_cflag & PARODD)) + lcr |= MAX310X_LCR_EVENPARITY_BIT; + } + + /* Stop bits */ + if (termios->c_cflag & CSTOPB) + lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */ + + /* Update LCR register */ + regmap_write(s->regmap, MAX310X_LCR_REG, lcr); + + /* Set read status mask */ + port->read_status_mask = MAX310X_LSR_RXOVR_BIT; + if (termios->c_iflag & INPCK) + port->read_status_mask |= MAX310X_LSR_RXPAR_BIT | + MAX310X_LSR_FRERR_BIT; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= MAX310X_LSR_RXBRK_BIT; + + /* Set status ignore mask */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNBRK) + port->ignore_status_mask |= MAX310X_LSR_RXBRK_BIT; + if (!(termios->c_cflag & CREAD)) + port->ignore_status_mask |= MAX310X_LSR_RXPAR_BIT | + MAX310X_LSR_RXOVR_BIT | + MAX310X_LSR_FRERR_BIT | + MAX310X_LSR_RXBRK_BIT; + + /* Configure flow control */ + regmap_write(s->regmap, MAX310X_XON1_REG, termios->c_cc[VSTART]); + regmap_write(s->regmap, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]); + if (termios->c_cflag & CRTSCTS) + flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT | + MAX310X_FLOWCTRL_AUTORTS_BIT; + if (termios->c_iflag & IXON) + flow |= MAX310X_FLOWCTRL_SWFLOW3_BIT | + MAX310X_FLOWCTRL_SWFLOWEN_BIT; + if (termios->c_iflag & IXOFF) + flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT | + MAX310X_FLOWCTRL_SWFLOWEN_BIT; + regmap_write(s->regmap, MAX310X_FLOWCTRL_REG, flow); + + /* Get baud rate generator configuration */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 4); + + /* Setup baudrate generator */ + max310x_set_baud(s, baud); + + /* Update timeout according to new baud rate */ + uart_update_timeout(port, termios->c_cflag, baud); + + mutex_unlock(&s->max310x_mutex); +} + +static int max310x_startup(struct uart_port *port) +{ + unsigned int val, line = port->line; + struct max310x_port *s = container_of(port, struct max310x_port, port); + + if (s->pdata->suspend) + s->pdata->suspend(0); + + mutex_lock(&s->max310x_mutex); + + /* Configure baud rate, 9600 as default */ + max310x_set_baud(s, 9600); + + /* Configure LCR register, 8N1 mode by default */ + val = MAX310X_LCR_WORD_LEN_8; + regmap_write(s->regmap, MAX310X_LCR_REG, val); + + /* Configure MODE1 register */ + regmap_update_bits(s->regmap, MAX310X_MODE1_REG, + MAX310X_MODE1_TRNSCVCTRL_BIT, + (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL) + ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0); + + /* Configure MODE2 register */ + val = MAX310X_MODE2_RXEMPTINV_BIT; + if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK) + val |= MAX310X_MODE2_LOOPBACK_BIT; + if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS) + val |= MAX310X_MODE2_ECHOSUPR_BIT; + + /* Reset FIFOs */ + val |= MAX310X_MODE2_FIFORST_BIT; + regmap_write(s->regmap, MAX310X_MODE2_REG, val); + + /* Configure FIFO trigger level register */ + /* RX FIFO trigger for 16 words, TX FIFO trigger for 64 words */ + val = MAX310X_FIFOTRIGLVL_RX(16) | MAX310X_FIFOTRIGLVL_TX(64); + regmap_write(s->regmap, MAX310X_FIFOTRIGLVL_REG, val); + + /* Configure flow control levels */ + /* Flow control halt level 96, resume level 48 */ + val = MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96); + regmap_write(s->regmap, MAX310X_FLOWLVL_REG, val); + + /* Clear timeout register */ + regmap_write(s->regmap, MAX310X_RXTO_REG, 0); + + /* Configure LSR interrupt enable register */ + /* Enable RX timeout interrupt */ + val = MAX310X_LSR_RXTO_BIT; + regmap_write(s->regmap, MAX310X_LSR_IRQEN_REG, val); + + /* Clear FIFO reset */ + regmap_update_bits(s->regmap, MAX310X_MODE2_REG, + MAX310X_MODE2_FIFORST_BIT, 0); + + /* Clear IRQ status register by reading it */ + regmap_read(s->regmap, MAX310X_IRQSTS_REG, &val); + + /* Configure interrupt enable register */ + /* Enable CTS change interrupt */ + val = MAX310X_IRQ_CTS_BIT; + /* Enable RX, TX interrupts */ + val |= MAX310X_IRQ_RX | MAX310X_IRQ_TX; + regmap_write(s->regmap, MAX310X_IRQEN_REG, val); + + mutex_unlock(&s->max310x_mutex); + + return 0; +} + +static void max310x_shutdown(struct uart_port *port) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + /* Disable all interrupts */ + mutex_lock(&s->max310x_mutex); + regmap_write(s->regmap, MAX310X_IRQEN_REG, 0); + mutex_unlock(&s->max310x_mutex); + + if (s->pdata->suspend) + s->pdata->suspend(1); +} + +static const char *max310x_type(struct uart_port *port) +{ + struct max310x_port *s = container_of(port, struct max310x_port, port); + + return (port->type == PORT_MAX310X) ? s->name : NULL; +} + +static int max310x_request_port(struct uart_port *port) +{ + /* Do nothing */ + return 0; +} + +static void max310x_release_port(struct uart_port *port) +{ + /* Do nothing */ +} + +static void max310x_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_MAX310X; +} + +static int max310x_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if ((ser->type == PORT_UNKNOWN) || (ser->type == PORT_MAX310X)) + return 0; + if (ser->irq == port->irq) + return 0; + + return -EINVAL; +} + +static struct uart_ops max310x_ops = { + .tx_empty = max310x_tx_empty, + .set_mctrl = max310x_set_mctrl, + .get_mctrl = max310x_get_mctrl, + .stop_tx = max310x_stop_tx, + .start_tx = max310x_start_tx, + .stop_rx = max310x_stop_rx, + .enable_ms = max310x_enable_ms, + .break_ctl = max310x_break_ctl, + .startup = max310x_startup, + .shutdown = max310x_shutdown, + .set_termios = max310x_set_termios, + .type = max310x_type, + .request_port = max310x_request_port, + .release_port = max310x_release_port, + .config_port = max310x_config_port, + .verify_port = max310x_verify_port, +}; + +static int max310x_suspend(struct spi_device *spi, pm_message_t state) +{ + int ret; + struct max310x_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "Suspend\n"); + + ret = uart_suspend_port(&s->uart, &s->port); + + mutex_lock(&s->max310x_mutex); + + /* Enable sleep mode */ + regmap_update_bits(s->regmap, MAX310X_MODE1_REG, + MAX310X_MODE1_FORCESLEEP_BIT, + MAX310X_MODE1_FORCESLEEP_BIT); + + mutex_unlock(&s->max310x_mutex); + + if (s->pdata->suspend) + s->pdata->suspend(1); + + return ret; +} + +static int max310x_resume(struct spi_device *spi) +{ + struct max310x_port *s = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "Resume\n"); + + if (s->pdata->suspend) + s->pdata->suspend(0); + + mutex_lock(&s->max310x_mutex); + + /* Disable sleep mode */ + regmap_update_bits(s->regmap, MAX310X_MODE1_REG, + MAX310X_MODE1_FORCESLEEP_BIT, + 0); + + max310x_wait_pll(s); + + mutex_unlock(&s->max310x_mutex); + + return uart_resume_port(&s->uart, &s->port); +} + +#ifdef CONFIG_GPIOLIB +static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned int val = 0; + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + regmap_read(s->regmap, MAX310X_GPIODATA_REG, &val); + mutex_unlock(&s->max310x_mutex); + + return !!((val >> 4) & (1 << offset)); +} + +static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ? + 1 << offset : 0); + mutex_unlock(&s->max310x_mutex); +} + +static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + + regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, 0); + + mutex_unlock(&s->max310x_mutex); + + return 0; +} + +static int max310x_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct max310x_port *s = container_of(chip, struct max310x_port, gpio); + + mutex_lock(&s->max310x_mutex); + + regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, + 1 << offset); + regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ? + 1 << offset : 0); + + mutex_unlock(&s->max310x_mutex); + + return 0; +} +#endif + +/* Generic platform data */ +static struct max310x_pdata generic_plat_data = { + .driver_flags = MAX310X_EXT_CLK, + .uart_flags[0] = MAX310X_ECHO_SUPRESS, + .frequency = 26000000, +}; + +static int __devinit max310x_probe(struct spi_device *spi) +{ + struct max310x_port *s; + struct device *dev = &spi->dev; + int chiptype = spi_get_device_id(spi)->driver_data; + struct max310x_pdata *pdata = dev->platform_data; + unsigned int val = 0; + int ret; + + /* Check for IRQ */ + if (spi->irq <= 0) { + dev_err(dev, "No IRQ specified\n"); + return -ENOTSUPP; + } + + /* Alloc port structure */ + s = devm_kzalloc(dev, sizeof(struct max310x_port), GFP_KERNEL); + if (!s) { + dev_err(dev, "Error allocating port structure\n"); + return -ENOMEM; + } + dev_set_drvdata(dev, s); + + if (!pdata) { + dev_warn(dev, "No platform data supplied, using defaults\n"); + pdata = &generic_plat_data; + } + s->pdata = pdata; + + /* Individual chip settings */ + switch (chiptype) { + case MAX310X_TYPE_MAX3107: + s->name = "MAX3107"; + s->nr_gpio = 4; + s->uart.nr = 1; + s->regcfg.max_register = 0x1f; + break; + case MAX310X_TYPE_MAX3108: + s->name = "MAX3108"; + s->nr_gpio = 4; + s->uart.nr = 1; + s->regcfg.max_register = 0x1e; + break; + default: + dev_err(dev, "Unsupported chip type %i\n", chiptype); + return -ENOTSUPP; + } + + /* Check input frequency */ + if ((pdata->driver_flags & MAX310X_EXT_CLK) && + ((pdata->frequency < 500000) || (pdata->frequency > 35000000))) + goto err_freq; + /* Check frequency for quartz */ + if (!(pdata->driver_flags & MAX310X_EXT_CLK) && + ((pdata->frequency < 1000000) || (pdata->frequency > 4000000))) + goto err_freq; + + mutex_init(&s->max310x_mutex); + + /* Setup SPI bus */ + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + spi->max_speed_hz = 26000000; + spi_setup(spi); + + /* Setup regmap */ + s->regcfg.reg_bits = 8; + s->regcfg.val_bits = 8; + s->regcfg.read_flag_mask = 0x00; + s->regcfg.write_flag_mask = 0x80; + s->regcfg.cache_type = REGCACHE_RBTREE; + s->regcfg.writeable_reg = max3107_8_reg_writeable; + s->regcfg.volatile_reg = max310x_reg_volatile; + s->regcfg.precious_reg = max310x_reg_precious; + s->regmap = devm_regmap_init_spi(spi, &s->regcfg); + if (IS_ERR(s->regmap)) { + ret = PTR_ERR(s->regmap); + dev_err(dev, "Failed to initialize register map\n"); + goto err_out; + } + + /* Reset chip & check SPI function */ + ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT); + if (ret) { + dev_err(dev, "SPI transfer failed\n"); + goto err_out; + } + /* Clear chip reset */ + regmap_write(s->regmap, MAX310X_MODE2_REG, 0); + + switch (chiptype) { + case MAX310X_TYPE_MAX3107: + /* Check REV ID to ensure we are talking to what we expect */ + regmap_read(s->regmap, MAX3107_REVID_REG, &val); + if (((val & MAX3107_REV_MASK) != MAX3107_REV_ID)) { + dev_err(dev, "%s ID 0x%02x does not match\n", + s->name, val); + ret = -ENODEV; + goto err_out; + } + break; + case MAX310X_TYPE_MAX3108: + /* MAX3108 have not REV ID register, we just check default value + * from clocksource register to make sure everything works. + */ + regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val); + if (val != (MAX310X_CLKSRC_EXTCLK_BIT | + MAX310X_CLKSRC_PLLBYP_BIT)) { + dev_err(dev, "%s not present\n", s->name); + ret = -ENODEV; + goto err_out; + } + break; + } + + /* Board specific configure */ + if (pdata->init) + pdata->init(); + if (pdata->suspend) + pdata->suspend(0); + + /* Calculate referecne clock */ + s->uartclk = max310x_set_ref_clk(s); + + /* Disable all interrupts */ + regmap_write(s->regmap, MAX310X_IRQEN_REG, 0); + + /* Setup MODE1 register */ + val = MAX310X_MODE1_IRQSEL_BIT; /* Enable IRQ pin */ + if (pdata->driver_flags & MAX310X_AUTOSLEEP) + val = MAX310X_MODE1_AUTOSLEEP_BIT; + regmap_write(s->regmap, MAX310X_MODE1_REG, val); + + /* Setup interrupt */ + ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(dev), s); + if (ret) { + dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq); + goto err_out; + } + + /* Register UART driver */ + s->uart.owner = THIS_MODULE; + s->uart.driver_name = dev_name(dev); + s->uart.dev_name = "ttyMAX"; + s->uart.major = MAX310X_MAJOR; + s->uart.minor = MAX310X_MINOR; + ret = uart_register_driver(&s->uart); + if (ret) { + dev_err(dev, "Registering UART driver failed\n"); + goto err_out; + } + + /* Initialize workqueue for start TX */ + s->wq = create_freezable_workqueue(dev_name(dev)); + INIT_WORK(&s->tx_work, max310x_wq_proc); + + /* Initialize UART port data */ + s->port.line = 0; + s->port.dev = dev; + s->port.irq = spi->irq; + s->port.type = PORT_MAX310X; + s->port.fifosize = MAX310X_FIFO_SIZE; + s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; + s->port.iotype = UPIO_PORT; + s->port.membase = (void __iomem *)0xffffffff; /* Bogus value */ + s->port.uartclk = s->uartclk; + s->port.ops = &max310x_ops; + uart_add_one_port(&s->uart, &s->port); + +#ifdef CONFIG_GPIOLIB + /* Setup GPIO cotroller */ + if (pdata->gpio_base) { + s->gpio.owner = THIS_MODULE; + s->gpio.dev = dev; + s->gpio.label = dev_name(dev); + s->gpio.direction_input = max310x_gpio_direction_input; + s->gpio.get = max310x_gpio_get; + s->gpio.direction_output= max310x_gpio_direction_output; + s->gpio.set = max310x_gpio_set; + s->gpio.base = pdata->gpio_base; + s->gpio.ngpio = s->nr_gpio; + if (gpiochip_add(&s->gpio)) { + /* Indicate that we should not call gpiochip_remove */ + s->gpio.base = 0; + } + } else + dev_info(dev, "GPIO support not enabled\n"); +#endif + + /* Go to suspend mode */ + if (pdata->suspend) + pdata->suspend(1); + + return 0; + +err_freq: + dev_err(dev, "Frequency parameter incorrect\n"); + ret = -EINVAL; + +err_out: + dev_set_drvdata(dev, NULL); + devm_kfree(dev, s); + + return ret; +} + +static int __devexit max310x_remove(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct max310x_port *s = dev_get_drvdata(dev); + + dev_dbg(dev, "Removing port\n"); + + devm_free_irq(dev, s->port.irq, s); + + destroy_workqueue(s->wq); + + uart_remove_one_port(&s->uart, &s->port); + + uart_unregister_driver(&s->uart); + +#ifdef CONFIG_GPIOLIB + if (s->pdata->gpio_base) + gpiochip_remove(&s->gpio); +#endif + + dev_set_drvdata(dev, NULL); + + if (s->pdata->suspend) + s->pdata->suspend(1); + if (s->pdata->exit) + s->pdata->exit(); + + devm_kfree(dev, s); + + return 0; +} + +static const struct spi_device_id max310x_id_table[] = { + { "max3107", MAX310X_TYPE_MAX3107 }, + { "max3108", MAX310X_TYPE_MAX3108 }, +}; +MODULE_DEVICE_TABLE(spi, max310x_id_table); + +static struct spi_driver max310x_driver = { + .driver = { + .name = "max310x", + .owner = THIS_MODULE, + }, + .probe = max310x_probe, + .remove = __devexit_p(max310x_remove), + .suspend = max310x_suspend, + .resume = max310x_resume, + .id_table = max310x_id_table, +}; +module_spi_driver(max310x_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("MAX310X serial driver"); diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h new file mode 100644 index 0000000..91648bf --- /dev/null +++ b/include/linux/platform_data/max310x.h @@ -0,0 +1,67 @@ +/* + * Maxim (Dallas) MAX3107/8 serial driver + * + * Copyright (C) 2012 Alexander Shiyan + * + * Based on max3100.c, by Christian Pellegrin + * Based on max3110.c, by Feng Tang + * Based on max3107.c, by Aavamobile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MAX310X_H_ +#define _MAX310X_H_ + +/* + * Example board initialization data: + * + * static struct max310x_pdata max3107_pdata = { + * .driver_flags = MAX310X_EXT_CLK, + * .uart_flags[0] = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL, + * .frequency = 3686400, + * .gpio_base = -1, + * }; + * + * static struct spi_board_info spi_device_max3107[] = { + * { + * .modalias = "max3107", + * .irq = IRQ_EINT3, + * .bus_num = 1, + * .chip_select = 1, + * .platform_data = &max3107_pdata, + * }, + * }; + */ + +#define MAX310X_MAX_UARTS 1 + +/* MAX310X platform data structure */ +struct max310x_pdata { + /* Flags global to driver */ + const u8 driver_flags:2; +#define MAX310X_EXT_CLK (0x00000001) /* External clock enable */ +#define MAX310X_AUTOSLEEP (0x00000002) /* Enable AutoSleep mode */ + /* Flags global to UART port */ + const u8 uart_flags[MAX310X_MAX_UARTS]; +#define MAX310X_LOOPBACK (0x00000001) /* Loopback mode enable */ +#define MAX310X_ECHO_SUPRESS (0x00000002) /* Enable echo supress */ +#define MAX310X_AUTO_DIR_CTRL (0x00000004) /* Enable Auto direction + * control (RS-485) + */ + /* Frequency (extrenal clock or crystal) */ + const int frequency; + /* GPIO base number (can be negative) */ + const int gpio_base; + /* Called during startup */ + void (*init)(void); + /* Called before finish */ + void (*exit)(void); + /* Suspend callback */ + void (*suspend)(int do_suspend); +}; + +#endif diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 0253c20..7cf0b68 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -193,8 +193,8 @@ /* SH-SCI */ #define PORT_SCIFB 93 -/* MAX3107 */ -#define PORT_MAX3107 94 +/* MAX310X */ +#define PORT_MAX310X 94 /* High Speed UART for Medfield */ #define PORT_MFD 95 -- cgit v0.10.2 From 63d486964cbd0d8556f28bf215c37b0d63f6bbba Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Tue, 14 Aug 2012 16:18:32 -0700 Subject: firmware: remove computone driver firmware and documentation The only Computone support left in the kernel is in drivers/tty/serial/8250/8250_pci.c. CONFIG_COMPUTONE is no longer a valid option. Therefore, remove firmware, documentation, and the last vestiges of this driver. Cc: Rob Landley Cc: Paul Gortmaker Cc: Ben Hutchings Cc: James Bottomley Cc: Dan Williams Signed-off-by: Tim Gardner Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/serial/00-INDEX b/Documentation/serial/00-INDEX index e09468a..f7b0c7d 100644 --- a/Documentation/serial/00-INDEX +++ b/Documentation/serial/00-INDEX @@ -2,8 +2,6 @@ - this file. README.cycladesZ - info on Cyclades-Z firmware loading. -computone.txt - - info on Computone Intelliport II/Plus Multiport Serial Driver. digiepca.txt - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards. hayes-esp.txt diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt deleted file mode 100644 index a6a1158..0000000 --- a/Documentation/serial/computone.txt +++ /dev/null @@ -1,520 +0,0 @@ -NOTE: This is an unmaintained driver. It is not guaranteed to work due to -changes made in the tty layer in 2.6. If you wish to take over maintenance of -this driver, contact Michael Warfield . - -Changelog: ----------- -11-01-2001: Original Document - -10-29-2004: Minor misspelling & format fix, update status of driver. - James Nelson - -Computone Intelliport II/Plus Multiport Serial Driver ------------------------------------------------------ - -Release Notes For Linux Kernel 2.2 and higher. -These notes are for the drivers which have already been integrated into the -kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4. - -Version: 1.2.14 -Date: 11/01/2001 -Historical Author: Andrew Manison -Primary Author: Doug McNash - -This file assumes that you are using the Computone drivers which are -integrated into the kernel sources. For updating the drivers or installing -drivers into kernels which do not already have Computone drivers, please -refer to the instructions in the README.computone file in the driver patch. - - -1. INTRODUCTION - -This driver supports the entire family of Intelliport II/Plus controllers -with the exception of the MicroChannel controllers. It does not support -products previous to the Intelliport II. - -This driver was developed on the v2.0.x Linux tree and has been tested up -to v2.4.14; it will probably not work with earlier v1.X kernels,. - - -2. QUICK INSTALLATION - -Hardware - If you have an ISA card, find a free interrupt and io port. - List those in use with `cat /proc/interrupts` and - `cat /proc/ioports`. Set the card dip switches to a free - address. You may need to configure your BIOS to reserve an - irq for an ISA card. PCI and EISA parameters are set - automagically. Insert card into computer with the power off - before or after drivers installation. - - Note the hardware address from the Computone ISA cards installed into - the system. These are required for editing ip2.c or editing - /etc/modprobe.d/*.conf, or for specification on the modprobe - command line. - - Note that the /etc/modules.conf should be used for older (pre-2.6) - kernels. - -Software - - -Module installation: - -a) Determine free irq/address to use if any (configure BIOS if need be) -b) Run "make config" or "make menuconfig" or "make xconfig" - Select (m) module for CONFIG_COMPUTONE under character - devices. CONFIG_PCI and CONFIG_MODULES also may need to be set. -c) Set address on ISA cards then: - edit /usr/src/linux/drivers/char/ip2.c if needed - or - edit config file in /etc/modprobe.d/ if needed (module). - or both to match this setting. -d) Run "make modules" -e) Run "make modules_install" -f) Run "/sbin/depmod -a" -g) install driver using `modprobe ip2 ` (options listed below) -h) run ip2mkdev (either the script below or the binary version) - - -Kernel installation: - -a) Determine free irq/address to use if any (configure BIOS if need be) -b) Run "make config" or "make menuconfig" or "make xconfig" - Select (y) kernel for CONFIG_COMPUTONE under character - devices. CONFIG_PCI may need to be set if you have PCI bus. -c) Set address on ISA cards then: - edit /usr/src/linux/drivers/char/ip2.c - (Optional - may be specified on kernel command line now) -d) Run "make zImage" or whatever target you prefer. -e) mv /usr/src/linux/arch/x86/boot/zImage to /boot. -f) Add new config for this kernel into /etc/lilo.conf, run "lilo" - or copy to a floppy disk and boot from that floppy disk. -g) Reboot using this kernel -h) run ip2mkdev (either the script below or the binary version) - -Kernel command line options: - -When compiling the driver into the kernel, io and irq may be -compiled into the driver by editing ip2.c and setting the values for -io and irq in the appropriate array. An alternative is to specify -a command line parameter to the kernel at boot up. - - ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 - -Note that this order is very different from the specifications for the -modload parameters which have separate IRQ and IO specifiers. - -The io port also selects PCI (1) and EISA (2) boards. - - io=0 No board - io=1 PCI board - io=2 EISA board - else ISA board io address - -You only need to specify the boards which are present. - - Examples: - - 2 PCI boards: - - ip2=1,0,1,0 - - 1 ISA board at 0x310 irq 5: - - ip2=0x310,5 - -This can be added to and "append" option in lilo.conf similar to this: - - append="ip2=1,0,1,0" - - -3. INSTALLATION - -Previously, the driver sources were packaged with a set of patch files -to update the character drivers' makefile and configuration file, and other -kernel source files. A build script (ip2build) was included which applies -the patches if needed, and build any utilities needed. -What you receive may be a single patch file in conventional kernel -patch format build script. That form can also be applied by -running patch -p1 < ThePatchFile. Otherwise run ip2build. - -The driver can be installed as a module (recommended) or built into the -kernel. This is selected as for other drivers through the `make config` -command from the root of the Linux source tree. If the driver is built -into the kernel you will need to edit the file ip2.c to match the boards -you are installing. See that file for instructions. If the driver is -installed as a module the configuration can also be specified on the -modprobe command line as follows: - - modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4 - -where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11, -12,15) and addr1-4 are the base addresses for up to four controllers. If -the irqs are not specified the driver uses the default in ip2.c (which -selects polled mode). If no base addresses are specified the defaults in -ip2.c are used. If you are autoloading the driver module with kerneld or -kmod the base addresses and interrupt number must also be set in ip2.c -and recompile or just insert and options line in /etc/modprobe.d/*.conf or both. -The options line is equivalent to the command line and takes precedence over -what is in ip2.c. - -config sample to put /etc/modprobe.d/*.conf: - options ip2 io=1,0x328 irq=1,10 - alias char-major-71 ip2 - alias char-major-72 ip2 - alias char-major-73 ip2 - -The equivalent in ip2.c: - -static int io[IP2_MAX_BOARDS]= { 1, 0x328, 0, 0 }; -static int irq[IP2_MAX_BOARDS] = { 1, 10, -1, -1 }; - -The equivalent for the kernel command line (in lilo.conf): - - append="ip2=1,1,0x328,10" - - -Note: Both io and irq should be updated to reflect YOUR system. An "io" - address of 1 or 2 indicates a PCI or EISA card in the board table. - The PCI or EISA irq will be assigned automatically. - -Specifying an invalid or in-use irq will default the driver into -running in polled mode for that card. If all irq entries are 0 then -all cards will operate in polled mode. - -If you select the driver as part of the kernel run : - - make zlilo (or whatever you do to create a bootable kernel) - -If you selected a module run : - - make modules && make modules_install - -The utility ip2mkdev (see 5 and 7 below) creates all the device nodes -required by the driver. For a device to be created it must be configured -in the driver and the board must be installed. Only devices corresponding -to real IntelliPort II ports are created. With multiple boards and expansion -boxes this will leave gaps in the sequence of device names. ip2mkdev uses -Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and -cuf0 - cuf255 for callout devices. - - -4. USING THE DRIVERS - -As noted above, the driver implements the ports in accordance with Linux -conventions, and the devices should be interchangeable with the standard -serial devices. (This is a key point for problem reporting: please make -sure that what you are trying do works on the ttySx/cuax ports first; then -tell us what went wrong with the ip2 ports!) - -Higher speeds can be obtained using the setserial utility which remaps -38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed. -Intelliport II installations using the PowerPort expansion module can -use the custom speed setting to select the highest speeds: 153,600 bps, -230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for -custom baud rate configuration is fixed at 921,600 for cards/expansion -modules with ST654's and 115200 for those with Cirrus CD1400's. This -corresponds to the maximum bit rates those chips are capable. -For example if the baud base is 921600 and the baud divisor is 18 then -the custom rate is 921600/18 = 51200 bps. See the setserial man page for -complete details. Of course if stty accepts the higher rates now you can -use that as well as the standard ioctls(). - - -5. ip2mkdev and assorted utilities... - -Several utilities, including the source for a binary ip2mkdev utility are -available under .../drivers/char/ip2. These can be build by changing to -that directory and typing "make" after the kernel has be built. If you do -not wish to compile the binary utilities, the shell script below can be -cut out and run as "ip2mkdev" to create the necessary device files. To -use the ip2mkdev script, you must have procfs enabled and the proc file -system mounted on /proc. - - -6. NOTES - -This is a release version of the driver, but it is impossible to test it -in all configurations of Linux. If there is any anomalous behaviour that -does not match the standard serial port's behaviour please let us know. - - -7. ip2mkdev shell script - -Previously, this script was simply attached here. It is now attached as a -shar archive to make it easier to extract the script from the documentation. -To create the ip2mkdev shell script change to a convenient directory (/tmp -works just fine) and run the following command: - - unshar Documentation/serial/computone.txt - (This file) - -You should now have a file ip2mkdev in your current working directory with -permissions set to execute. Running that script with then create the -necessary devices for the Computone boards, interfaces, and ports which -are present on you system at the time it is run. - - -#!/bin/sh -# This is a shell archive (produced by GNU sharutils 4.2.1). -# To extract the files from this archive, save it to some FILE, remove -# everything before the `!/bin/sh' line above, then type `sh FILE'. -# -# Made on 2001-10-29 10:32 EST by . -# Source directory was `/home2/src/tmp'. -# -# Existing files will *not* be overwritten unless `-c' is specified. -# -# This shar contains: -# length mode name -# ------ ---------- ------------------------------------------ -# 4251 -rwxr-xr-x ip2mkdev -# -save_IFS="${IFS}" -IFS="${IFS}:" -gettext_dir=FAILED -locale_dir=FAILED -first_param="$1" -for dir in $PATH -do - if test "$gettext_dir" = FAILED && test -f $dir/gettext \ - && ($dir/gettext --version >/dev/null 2>&1) - then - set `$dir/gettext --version 2>&1` - if test "$3" = GNU - then - gettext_dir=$dir - fi - fi - if test "$locale_dir" = FAILED && test -f $dir/shar \ - && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) - then - locale_dir=`$dir/shar --print-text-domain-dir` - fi -done -IFS="$save_IFS" -if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED -then - echo=echo -else - TEXTDOMAINDIR=$locale_dir - export TEXTDOMAINDIR - TEXTDOMAIN=sharutils - export TEXTDOMAIN - echo="$gettext_dir/gettext -s" -fi -if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then - shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"' -elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then - shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"' -elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then - shar_touch='touch -am $3$4$5$6$2 "$8"' -else - shar_touch=: - echo - $echo 'WARNING: not restoring timestamps. Consider getting and' - $echo "installing GNU \`touch', distributed in GNU File Utilities..." - echo -fi -rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch -# -if mkdir _sh17581; then - $echo 'x -' 'creating lock directory' -else - $echo 'failed to create lock directory' - exit 1 -fi -# ============= ip2mkdev ============== -if test -f 'ip2mkdev' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'ip2mkdev' '(file already exists)' -else - $echo 'x -' extracting 'ip2mkdev' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' && -#!/bin/sh - -# -# ip2mkdev -# -# Make or remove devices as needed for Computone Intelliport drivers -# -# First rule! If the dev file exists and you need it, don't mess -# with it. That prevents us from screwing up open ttys, ownership -# and permissions on a running system! -# -# This script will NOT remove devices that no longer exist if their -# board or interface box has been removed. If you want to get rid -# of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*" -# before running this script. Running this script will then recreate -# all the valid devices. -# -# Michael H. Warfield -# /\/\|=mhw=|\/\/ -# mhw@wittsend.com -# -# Updated 10/29/2000 for version 1.2.13 naming convention -# under devfs. /\/\|=mhw=|\/\/ -# -# Updated 03/09/2000 for devfs support in ip2 drivers. /\/\|=mhw=|\/\/ -# -X -if test -d /dev/ip2 ; then -# This is devfs mode... We don't do anything except create symlinks -# from the real devices to the old names! -X cd /dev -X echo "Creating symbolic links to devfs devices" -X for i in `ls ip2` ; do -X if test ! -L ip2$i ; then -X # Remove it incase it wasn't a symlink (old device) -X rm -f ip2$i -X ln -s ip2/$i ip2$i -X fi -X done -X for i in `( cd tts ; ls F* )` ; do -X if test ! -L tty$i ; then -X # Remove it incase it wasn't a symlink (old device) -X rm -f tty$i -X ln -s tts/$i tty$i -X fi -X done -X for i in `( cd cua ; ls F* )` ; do -X DEVNUMBER=`expr $i : 'F\(.*\)'` -X if test ! -L cuf$DEVNUMBER ; then -X # Remove it incase it wasn't a symlink (old device) -X rm -f cuf$DEVNUMBER -X ln -s cua/$i cuf$DEVNUMBER -X fi -X done -X exit 0 -fi -X -if test ! -f /proc/tty/drivers -then -X echo "\ -Unable to check driver status. -Make sure proc file system is mounted." -X -X exit 255 -fi -X -if test ! -f /proc/tty/driver/ip2 -then -X echo "\ -Unable to locate ip2 proc file. -Attempting to load driver" -X -X if /sbin/insmod ip2 -X then -X if test ! -f /proc/tty/driver/ip2 -X then -X echo "\ -Unable to locate ip2 proc file after loading driver. -Driver initialization failure or driver version error. -" -X exit 255 -X fi -X else -X echo "Unable to load ip2 driver." -X exit 255 -X fi -fi -X -# Ok... So we got the driver loaded and we can locate the procfs files. -# Next we need our major numbers. -X -TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` -CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^ ]*[ ]*\([0-9]*\)[ ]*.*/\1/' < /proc/tty/drivers` -BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[ ]*.*/\1/' < /proc/tty/driver/ip2` -X -echo "\ -TTYMAJOR = $TTYMAJOR -CUAMAJOR = $CUAMAJOR -BRDMAJOR = $BRDMAJOR -" -X -# Ok... Now we should know our major numbers, if appropriate... -# Now we need our boards and start the device loops. -X -grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest -do -X # The test for blank "type" will catch the stats lead-in lines -X # if they exist in the file -X if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = "" -X then -X continue -X fi -X -X BOARDNO=`expr "$number" : '\([0-9]\):'` -X PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '` -X MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '` -X -X if test "$BOARDNO" = "" -o "$PORTS" = "" -X then -# This may be a bug. We should at least get this much information -X echo "Unable to process board line" -X continue -X fi -X -X if test "$MINORS" = "" -X then -# Silently skip this one. This board seems to have no boxes -X continue -X fi -X -X echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS" -X -X if test "$BRDMAJOR" != "" -X then -X BRDMINOR=`expr $BOARDNO \* 4` -X STSMINOR=`expr $BRDMINOR + 1` -X if test ! -c /dev/ip2ipl$BOARDNO ; then -X mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR -X fi -X if test ! -c /dev/ip2stat$BOARDNO ; then -X mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR -X fi -X fi -X -X if test "$TTYMAJOR" != "" -X then -X PORTNO=$BOARDBASE -X -X for PORTNO in $MINORS -X do -X if test ! -c /dev/ttyF$PORTNO ; then -X # We got the hardware but no device - make it -X mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO -X fi -X done -X fi -X -X if test "$CUAMAJOR" != "" -X then -X PORTNO=$BOARDBASE -X -X for PORTNO in $MINORS -X do -X if test ! -c /dev/cuf$PORTNO ; then -X # We got the hardware but no device - make it -X mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO -X fi -X done -X fi -done -X -Xexit 0 -SHAR_EOF - (set 20 01 10 29 10 32 01 'ip2mkdev'; eval "$shar_touch") && - chmod 0755 'ip2mkdev' || - $echo 'restore of' 'ip2mkdev' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'ip2mkdev:' 'MD5 check failed' -cb5717134509f38bad9fde6b1f79b4a4 ip2mkdev -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`" - test 4251 -eq "$shar_count" || - $echo 'ip2mkdev:' 'original size' '4251,' 'current size' "$shar_count!" - fi -fi -rm -fr _sh17581 -exit 0 diff --git a/firmware/Makefile b/firmware/Makefile index 344713b..fdc9ff0 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -40,7 +40,6 @@ fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \ bnx2/bnx2-mips-06-6.2.1.fw \ bnx2/bnx2-rv2p-06-6.0.15.fw fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin -fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ cxgb3/t3c_psram-1.1.0.bin \ cxgb3/t3fw-7.10.0.bin \ diff --git a/firmware/intelliport2.bin.ihex b/firmware/intelliport2.bin.ihex deleted file mode 100644 index e9cfe8c..0000000 --- a/firmware/intelliport2.bin.ihex +++ /dev/null @@ -1,2147 +0,0 @@ -:100000003C4237180201030000000000000000001D -:10001000576564204465632030312031323A3234F0 -:100020003A33302031393939000000000000000037 -:10003000E96C0F426547694E6E496E47206F462056 -:10004000634F6445CC135A15E8167618041A921BB0 -:10005000201DAE1E3C20CA215823E6247426022807 -:1000600090291E2BAC2C3A2EC82F5631E432723414 -:1000700000368E371C39AA3A383CC63D543FE24020 -:100080007042FE438C451A47A848364AC44B524D2D -:10009000E04E6E50FC518A531855A6563458C2593A -:1000A000505BDE5C6C5EFA5F88611663A464326646 -:1000B000C0674E69DC6A6A6CF86D866F1471A27253 -:1000C0003074BE754C776C778C77AC7733DB8ADC19 -:1000D0005333DB250700750A8A1E080183E30CEB06 -:1000E00020903C01750A8A1E080180E3C0EB129043 -:1000F0008A1E0D013C02750680E30CEB049080E340 -:10010000C053508B1EBA138EDBE86A65558BEC53D7 -:100110001E2BC08ED88B5E04C1E304035E06D1E3C0 -:100120002E8B9F44008D472A1E5A1F5B5DC3558B43 -:10013000EC531E2BC08ED88B5E04C1E304035E0615 -:10014000D1E32E8B9F44008D47341E5A1F5B5DC345 -:10015000FB558BEC53515256571E061E0733C08E6B -:10016000D88B5E04268A47592503008BF0D1E62EF2 -:100170008BB4C400C1E0042602471AD1E08BE82EFC -:100180008BAE4400892C268A471C88440F268A4758 -:100190001D884410268A471E884411268A471F88D6 -:1001A0004412268A4720884413268A472388441409 -:1001B000268A4724884415268A475A88440E33C025 -:1001C00089440689440888440B88440AB021B464F1 -:1001D000894404894402B05588440D88440CE86A77 -:1001E00000725BE8C900E8C110894408807C0F01F7 -:1001F0007429E82B02E87F02807C0F03741DE8A9B4 -:10020000108BF82B44083DA00F7210897C0833C076 -:1002100087440685C07504C6440AFF8A440A84C020 -:10022000750BB80800E86A4AE8A90173BFE84F01F6 -:100230008166487FFF83667ABFB002E8040E8A4475 -:100240000A98071F5F5E5A595B5DC3814E48800064 -:10025000B040E83D4AE88940732AE84D108BD8B099 -:1002600005E82E4AF6462702751AE83D102BC33DD5 -:10027000581B72EB8166487FFFB002E8C40DC6448C -:100280000A01F9C3834E7A40F8C3FBB001E8024A81 -:10029000FAE8991EE40A84C075F0B04EE60AFBB095 -:1002A00001E8EE49FAE8851EE40A84C075F0C3FA55 -:1002B000E87A1EE4EC884416E4E4884417E4F888FD -:1002C0004418E4F0884419E41088441AE41288447D -:1002D0001BE41488441CE43488441DE43688441E1E -:1002E000E4D824018AE0E4DA24020AC488441F8A9C -:1002F0004410E8CD1F8A4411E835218A4412E88968 -:10030000218A4413E84321C686A10000E414241086 -:10031000E614E412243DE6128A44153C01721E776D -:1003200016B011E634B013E636E4140C10E614E40B -:10033000120C40E612EB06E4120C02E6128A440F9D -:100340003C0174063C02740AEB0EE4120C08E6123F -:10035000EB06E4120C10E612E82FFF8A44143C026C -:100360007508B05588440C88440DB021B4648944A4 -:1003700004894402E40C0C10E60CE8ED39FBC3E8F8 -:100380005F3F7308FBB00AE80849EBF3FAE89D1DEC -:100390008A64168A441789869400E6E48AC4E6ECE7 -:1003A0008A64188A441989869600E6F08AC4E6F8B9 -:1003B0008A441AE6108A441BE6128A441CE6148A10 -:1003C000441DE6348A441EE6368A441FE6D8E6DA3F -:1003D000E9B7FE90FA8A440EE6FEE402A80175052C -:1003E00033C0FBF8C333C0E400FBF9C38A64148054 -:1003F000FC02742BFEC0FEC780FF4E721C74098085 -:10040000FF507308B00AEB17B00DEB1302DC32FF9C -:1004100080FB7F7C02B3218AC33C7F7C02B021C376 -:10042000FA807C0B047602FBC38B46243D080072E5 -:10043000F68E46028B7E228A440C8B5C02AAE8ABC5 -:10044000FFAAE8A7FFAAE8A3FFAAE89FFF88440C39 -:10045000895C0280440B04897E22836E24048346D7 -:100460001A04807E26027406806626FDFBC360B0F7 -:10047000FDE8023F61FBC3FA807C0F037509C644A7 -:100480000B00E8E538FBC3C47E148B4E3A85C97572 -:1004900035268B0D4747E3EA3B7E047622B80200FF -:1004A00039462E7707C7462E0000EB138B5E2C894A -:1004B0005E0426C70700004343895E2C29462E852B -:1004C000C978CE894E3A8A440D8B5C04268A25472A -:1004D0003AC47516FE4C0BFF4406E80FFFE2ED88A8 -:1004E000440D895C04894E3AEBA7C6440AFEE879BC -:1004F00038FBC390E8B30D8AE88A0ECB13B3078AA2 -:10050000C1EEEB00EC3AC1750902CDFECB75F0EB04 -:100510000C90880ECB138AE8BBFFFFF9C3880ECB83 -:1005200013F8C390BB3F3F8A8E9E00BAFE00EC8A50 -:10053000E832C122C37502F8C3F9C390E8E5FF733E -:1005400001C3BAD000BB03038A8E9F00EC8AE83255 -:10055000C122C37502F8C3F9C39033C08ED88EC0D0 -:10056000803EC813007507B00AE82647EBF2FB335C -:10057000DB8A1EC913434383FB7E760733DBB0025D -:10058000E80F472E8BAF4400837E080074E7881E77 -:10059000C913B002E8FB46FAF7463840007414E885 -:1005A000961BE87FFF721C33D28A969F0083C20E8F -:1005B000EB0C90E8771BE883FF7208BA4800E83339 -:1005C000FF73AB23CB898E9A0089969C00FE86B57B -:1005D00000C606C81300B00AE8670AFBEB891018CA -:1005E000082833C0A005018AC824407524C7067CAA -:1005F000128E45C70642120100C606541202B00808 -:10060000F6C1017402B004A34612A24C12A29412C5 -:10061000C3C7067C12B645A00F0184C0750E6A00E0 -:100620001FC60693121E9C0EE8B10C90C70644121A -:100630000100A342128BD8C1E304881E9412BEE2CB -:10064000052BF08BC833DB8BFB2EAC888548128AD8 -:10065000D80C05E6FE8AE0EB00E4FE32C4A83F7445 -:1006600003E99E00E400888550128AE02430BA1025 -:10067000FF3C30741280FC04740ABA0403F60608C6 -:1006800001FE7403BA080F88954C1202FA32C0F6C4 -:10069000C4087402B001888558128AC43C35745B62 -:1006A0003C3674573C3474533C04744F3C14744BC4 -:1006B0003C157447A8407425C685541204D1E7B48C -:1006C000038AC389855C128AC38AE380CC01898549 -:1006D0006412D1EF47E203EB1A90E96CFFC6855430 -:1006E0001202D1E78AE68AC30C0489855C12D1EF35 -:1006F00047E2E733C08AC7A34612C3C68554120631 -:10070000EBBBC68554120033C08885501288854CD7 -:100710001288855812EBA6C7462602128B461E8900 -:1007200046008946228B4620894624C7461A000087 -:10073000C3C7463C8000C7463801001E568B763042 -:100740008976048976148E5E0633C089044646890C -:10075000762C89463A8B4632484889462E5E1FC31E -:1007600033C089464889464AC74646AE0189464E47 -:100770008B46448946508B4642894640894608C389 -:1007800033C0894676894678C7467A1000561E8B54 -:10079000767089761089760C8E5E12C70400008B05 -:1007A00046728946741F5EC3895618895602895657 -:1007B0000689560A89560E8956128956168BD84BC9 -:1007C0004BC1E302BF0200897E1E03FB897E30031A -:1007D000FB897E4203FB897E7083EB08895E20895A -:1007E0005E32895E44895E7250E82BFFE871FFE853 -:1007F0003FFFE88BFF58C3B83075C1E8040E5B03B8 -:10080000C3A3BA13833E4212007407803E941200C1 -:10081000750E6A001FC60693121E9C0EE8BD0A9054 -:10082000B8307AC1E80440A3C0132B061201F7D8F0 -:1008300033D28BCA8A0E9412F7F13D8000770E6A8C -:10084000001FC6069312259C0EE8900A90483DFFB3 -:10085000077203B8FF07A3C21333C98A0E94123379 -:10086000F6B800092E8BAC440089464C404646E25F -:10087000F38A0E941233F68B16C013A1C2132E8B7B -:10088000AC4400E822FF03D04646E2F2C333C02E58 -:100890008BAD44008946084747E2F4C35133C00A90 -:1008A000C22E8BAD440089869E00814E38002047C1 -:1008B00047FEC480FC04720432E4FEC0E2E35983C4 -:1008C000E9107405F7D9E8C4FFC35133C00AC22E3A -:1008D0008BAD440089869E00834E3840474780C4D4 -:1008E00010790432E4FEC0E2E65983E9107405F79A -:1008F000D9E899FFC3E8D2FFC38D089C08CA08F560 -:10090000088B0E421233F6515633DB8BCB8A944858 -:10091000128A8C4C128A9C54128BFEC1E70585DB2F -:100920007502B1102EFF97F9085E5946E2D9C3014E -:10093000CC03D000E802D000E801D000E800D000ED -:10094000E804D0A8DA00DC00DE01D803CC03CC0335 -:10095000CC04D0A8DA20DC00DE03CC03CC03CC002E -:10096000D803CC03CC03CC03CC03CC03CC03CC0303 -:10097000CC03CC03CC03CC03CC03CC03CC03CC03FF -:10098000CC04D000DA20DC03DE01D803CC03CC0396 -:10099000CC03CC00D800CC00D0000056521E0E1F55 -:1009A000BE2F0933D2FCAD85C0740D8AD4EEAD855F -:1009B000C074058AD4EEEBEE1F5A5EC3E48084C097 -:1009C00074167814B027E6FCB011E634E4FC3C273A -:1009D0007506E4117502F8C3F9C383C206B0BFEE11 -:1009E00083EA02B010EE8886AF00B01183C204EE35 -:1009F00083C202EEB01383C202EE83C202EE2EA1C6 -:100A00004C2D8986940083EA0EEE83C2028AC4EEDE -:100A100083C204B003EE8886A80083EA0432C0EEE5 -:100A200083C202B089EE8886A6000C06EEB040B400 -:100A30003889461CC74636380083C20432C0EE8867 -:100A400086A700C383C206B0BFEE83EA02EC3A86F3 -:100A5000AF00752483C204EC3C11751C83C206EC04 -:100A60003C13751483EA088A86A800EE83EA02EC38 -:100A700024C03CC07502F8C3F9C333C98BD18BF1D4 -:100A80008A0E9412C1E9022E8BAC4400F74638005E -:100A900020740E8A869E00E6FE32C0E68042E8FAA6 -:100AA000FE83C608E2E185D27403E80508C333C9B2 -:100AB0008BF18A0E94122E8BAC4400F7463840001E -:100AC0007406E87316E812FF4646E2EAC333C98BA0 -:100AD000F18A0E9412C1E9022E8BAC4400F746381D -:100AE00000207416E84616E8D2FE730E6A001FC690 -:100AF0000693121C9C0EE8E3079083C608E2D9C354 -:100B000033C98BF18A0E94122E8BAC4400F7463811 -:100B100040007416E82116E82AFF730E6A001FC60B -:100B20000693121C9C0EE8B307904646E2DAC30C0B -:100B300000001000131200001400283C001B3E00AF -:100B4000002A00002C0000420014D80000DA000047 -:100B50003400113600133800113A001300005650CB -:100B600052BE2F0B2EAD85C07406922EACEEEBF468 -:100B70005A585EC3532EA16022E6E4E6F08AC4E62A -:100B8000ECE6F8E8D8FFB04BE610B050E612B0380B -:100B9000E614E8AE15B046E60AE8A715B01AE60A6C -:100BA000E8A015B022E60AE89915E8FD068BD8E41E -:100BB00016A8047518E8F2062BC33D320072F06ADD -:100BC000001FC6069312239C0EE8100790E8DA0671 -:100BD0002BC33D2400771BB031E6FC565155B910AC -:100BE000002E8BAC4400814E3880004646E2F25D18 -:100BF000595EE869FFE84B15B046E60AE844155B24 -:100C0000C333F68B0E42122E8BAC4400F7463800ED -:100C1000207406E81715E85BFF83C620E2E9C38B62 -:100C2000C20504008946282EA14C2D89868E008994 -:100C300086900089869200C686A3000AC686C300F5 -:100C4000035283C2048A86A6000C06EE5A83C202AF -:100C5000B005EE8886A500C3E803FFE8E514B042BE -:100C6000E60AF74638800074062EA19C22EB042E7B -:100C7000A16C22C7461C0C008986940089869600C8 -:100C800089868E008986900089869200E6F0E6E4E7 -:100C90008AC4E6F8E6ECC686C30003E8A514B01AD9 -:100CA000E60AB0108886A500E60CC333C98BF18A2A -:100CB0000E94122E8BAC4400F7463840007406E8C0 -:100CC0007614E85AFF4646E2EAC333C98BF18A0E2E -:100CD00094122E8BAC4400F7463800207406E84C82 -:100CE00014E874FF4646E2EAC390833E441200755E -:100CF00014B001BA0601EE2AC0EEB002EEB004EE66 -:100D0000B80002EB0FBA0601B040EEB801008A0E3F -:100D10000E01D3E0A38812C3A18812A384122D2050 -:100D200000A38A122D2000A38212C706861220007B -:100D3000C70680123200C3833E44120074768B0EC5 -:100D4000421233F68AA4541284E4745F8A844812EF -:100D50000C04E6FEF6C4047425B01BBA0000EEEBEA -:100D6000002AC0BA0200EEEB00B003EEEB0032C086 -:100D7000BA0200EEEB00BA0000B000EEEB2DB01F9F -:100D8000BA0000EEEB002AC0BA0200EEEB00B0039E -:100D9000EEEB00D1E68A845D12D1EEF6D0BA020005 -:100DA000EEEB00BA0000B00AEEEB00E404EB00E466 -:100DB0000446E290C390B81400BA3EFFEFB80600B4 -:100DC000BA32FFEFB80F00BA34FFEFBA36FFEF8345 -:100DD0003E4412007516B81100BA38FFEFB8120081 -:100DE000BA3AFFEFB81B00BA3CFFEFC3B81100BA24 -:100DF00038FFEFB81200BA3AFFEFB81B00BA3CFF59 -:100E0000EFC3B8FC00BA28FFEFFB833E4412007426 -:100E100007B8CC00BA28FFEFC300FFFF202428FF4B -:100E20002CFFFF303438FFFF3C903C0F770EBB198E -:100E30000E2ED73CFF74058AD8F8C3902ADBF9C37D -:100E4000833E4412007427A00601802606013080EC -:100E50003E0601307518B90200BFC413BA0601EC92 -:100E6000A82075F8BA0401EDABE2F1EB1690B904D5 -:100E700000BFC413BA0601ECA82075F8BA0401EC4F -:100E8000AAE2F1FA90BEC413AD80E43F80FC027484 -:100E90000E6A001FC60693120A9C0EE83E0490AD2F -:100EA0003C0F75ED8AC4E881FF72E6881E1A01C600 -:100EB000068E1200B0000A061A01BA0001EEC6063C -:100EC0008F1240833E4412007506B80C00EB04906C -:100ED000B84C00BA28FFEFC3833E4412007501C32B -:100EE000A150120B0652120AC4A80874F2A00F01F6 -:100EF0002AE450FF36BA131FE8505683C4026A0032 -:100F00001F33C0A3BC13A00F01A3BE138B1EBC13C1 -:100F10008A875012F687501208740D24078AE0BEA3 -:100F2000CC00A0BC13E8943DFF06BC13FF0EBE131B -:100F300075DAC3901E33C08ED8B001E8543D1FC38C -:100F400033C98BF18A0E94122E8BAC4400C74662D3 -:100F50003844C7467CFC3BC7467EE23BC7868000E0 -:100F6000EC3CE8AB16C686C00011837E080074070F -:100F70005156E833335E594646E2CDC333C98BF14F -:100F80008BF98A0E9412C1E902E3132E8BAC440054 -:100F90008A869E0088856C1283C60847E2EDC3FAF4 -:100FA000FCB0C0BA0001EE33C08ED88EC08ED0BF68 -:100FB0001601B9CC772BCFD1E9F3ABBC4012E8D9FD -:100FC00002E8703CBECC0FE8F23CF49033C08ED8FF -:100FD0008EC08ED0F6060A0180740BBE3555E8DB54 -:100FE0003CB001E8AC3CE8B300E8F6F5E808F8E806 -:100FF0000FF9E885FAE8B6FAE8EFFCE8C210E80372 -:101000003CE8B2FDE830FDE85402C6068F12C0E8A5 -:10101000BBFAE8EBFAE8E9FBE8AFFCE88DFCE81F77 -:10102000FFE858FFE8DBFDE816FE33C0BE5A05E8CE -:101030008A3CE8A3FEE8E0FCFBBEA444E87D3CE972 -:10104000CA2D56988BF08B425285C07527C74252E5 -:10105000010053368B9C2C01F6C301750C36896850 -:10106000523689AC2C015B5EC33689AC2C013689C3 -:10107000AC1C015B5EC356988BF033ED368B841C41 -:1010800001A80175158BE833C08742523689841C4C -:1010900001A80174053689842C015EC3565133F6CC -:1010A000B80100B9080089841C0189842C014646D6 -:1010B000E2F4595EC390BB01008BE8FF4E6E740AE8 -:1010C0008BDD8B4658A80174F0C38B4648A90800F5 -:1010D0007445F7463840007427E85C1080C2068AE1 -:1010E00086A80024BF8886A800EE60B0FEE886329D -:1010F00061B002E84CFF8B464824F7894648EB175D -:10110000E82A10814E2600408A86A5000C028886B7 -:10111000A500E60C8B4648A904007414B002E8212F -:10112000FF8B464824FB89464860B0DFE8473261C0 -:1011300033C0874658F6C301750B36894758A80156 -:10114000750DE974FFA32201A8017503E96AFF89FF -:101150001E3201C3BB01008BE8F74638400074150E -:10116000E8D50F80C20AECA840750A8BDD8B465685 -:10117000A80174E3C38B462680E4FE80CC02894636 -:1011800026B002E8BCFE33C0874656F6C301750A96 -:1011900036894756A801750BEBBDA32001A8017540 -:1011A00002EBB4891E3001C3601E062BC08ED8A08E -:1011B000901284C07549A12201A8017503E8F6FECA -:1011C000A12001A8017503E88AFFA1AC13487805A6 -:1011D0007445A3AC13A1AE134878057451A3AE13A4 -:1011E000A1B0134878057463A3B013A17E124078B0 -:1011F00003A37E12B80080BA22FFEF071F61CFA0C1 -:101200009112403C02720B33C0A29112FF167C1265 -:10121000EBA4A29112EB9FA08E1232068F12A28E27 -:10122000120A061A01BA0001EEB82C01EBA4833EA3 -:101230008412107211BA28FFED0C81EFE85337BA0F -:1012400028FFED247EEFB80400EB92C6068D120154 -:10125000E83F37C6068D1200A1B213EB8B908A1EB1 -:101260000B012AFF6BC319BA62FFEFB80A00BA601C -:10127000FFEFB801E0BA66FFEFB8FFFFBA52FFEF29 -:10128000B809C0BA56FFEFC706AC132C01C706AEAB -:10129000130400C606911200C3908A1E0B012AFF98 -:1012A0006BC305D1E8A31801C39052BA50FFED5AA1 -:1012B000C39053518B1E1801B9320590E2FE4B7555 -:1012C000F7595BC3B080BA00010A061A01EEC39059 -:1012D000B040EBF2B0C0EBEEB000EBEAFA60061EF5 -:1012E000162BDB8EDB2EA1BA4C2EA3924CA09312B0 -:1012F000988BE889262D7A803ECA13007403E96B27 -:1013000042E8C0FFE8ABFFE8A8FFB020C606901295 -:1013100000FF167C128BFD83FF0A7211E8B9FFE80B -:1013200090FFE8ABFFE88AFF83EF0AEBEA0BFF745C -:101330000FE8A4FFE87BFFE89AFFE875FF4F75F11F -:10134000E895FFE86CFFEBB98A86A50024FDEE88DE -:1013500086A500C38A86A6000C02EEC38B7638F7FA -:10136000C6010074EF8B4E368B462E3BC173028B49 -:10137000C82BC189462E014E34C47E0426010D8B34 -:101380007E2C83EA04F36C8EC1897E2C3B463C7232 -:1013900012F7C62000750B83CE20897638B000E89E -:1013A000A0FCC3F7C60400741B8BD883CE108976CB -:1013B000388A86A70024FE8886A70083C208EE83A9 -:1013C000EA088BC33D40007201C3814E380004839C -:1013D000C2028A86A50024FA8886A500EEC38A8602 -:1013E000A6000C02EEC3F74638010074F18B4E2EB6 -:1013F00032DB8ABEA30083C206C476048B7E2C83B4 -:10140000F908722CECA80174168AE083EA0AEC83CE -:10141000C20A84E77551AAFEC34983F90873E5320D -:10142000FF26011C015E34897604894E2E897E2CAC -:101430003B4E3C7211F64638207401C3834E38206F -:10144000B000E8FDFBC3F64638047415834E38102F -:101450008A86A70024FE8886A70083EA02EE83C25C -:10146000023D4000725DC332FF26031C85DB740918 -:1014700026891C8BF74747494980E41E80CCC0264B -:101480008904F6C41074278B7638F7C60010740BE5 -:1014900050FE86B200B00AE8A8FB58F7C6000174F7 -:1014A0000DE882268B76388B4E2E8B7E04AB8BF725 -:1014B00033C0AB32DB8ABEA300494983F9087217F7 -:1014C000E941FF814E38000483C2F88A86A50024D2 -:1014D000FA8886A500EEC3E945FF83C208EC88863A -:1014E000AA00C0E8048AE08AC88686A90032E08B98 -:1014F0005E3E84E3744F8AC18B4E26F6C504740C9D -:10150000A808740580E1BFEB0380C940F6C50874E4 -:101510000CA802740580E17FEB0380C980884E2609 -:101520008BF08A86A50084C97408A802741524FD6E -:10153000EB06A802750D0C028886A50083EA0AEE68 -:1015400083C20A8BC684E77501C3C686BA0001B0A0 -:101550000EE8EEFAF74638000274EE837E2E06722D -:10156000E88AA6AA00C45E048B7E2CB0FFAAB00253 -:10157000AB26830703836E2E03897E2CF646382024 -:101580007401C3834E3820B000E8B6FAC39083EAF2 -:1015900008E9B4FD83C2068B5E26F6C3C075EF8BE7 -:1015A0004E1CEC8886A40083EA0AA82075028ACD26 -:1015B00032ED8B461A3BC87318014E2A2BC189465F -:1015C0001AC57600F36E8ED98976003D2000723000 -:1015D000C385C074318BC801462AC57600F36E8E70 -:1015E000D980CB02895E26E832F1F6C701751683F1 -:1015F000C202E853FDF6C710750BB002E843FAC308 -:10160000F6C70174F0C380CB02895E26F6C7017469 -:10161000DE83C202E831FDF686A40040740B80E749 -:10162000FE80CF02895E26EBCCB004E814FAC3C07A -:10163000C2C8CAC4C6CCCED0D2D8DAD4D6DCDE90EA -:10164000E90E01E4C48AE0E4C48BD083F90872F0A7 -:1016500026833F0074048BDF49498BFB8ADE83E3DA -:101660000F2E8AA72F16ABF6C4107424F7C60010ED -:10167000740B50FE86B200B00AE8C6F958F7C600EF -:1016800001740DE8A0248B76388B4E2E8B7E04AB34 -:10169000897E0433C0AB4949894E2E897E2C8BC18B -:1016A000EB4E90EB9E90E4D684C07963E6D08AC876 -:1016B00025030003D8D1E32E8BAF4400888EAE0003 -:1016C0008B4E2EC45E048B7E2C8B7638E4862407EA -:1016D0003C0375CFE41C913BC173028BC82BC189BD -:1016E000462E014E3426010FBAC400F36C897E2CBD -:1016F0003B463C721CF7C62000750B83CE208976D2 -:1017000038B000E83CF98A86AE00243FE6D6C3F93B -:10171000C3F7C60A007435F7C61000752F83CE10C4 -:10172000897638F7C60200740E50E4D824FEE6D855 -:1017300058F7C6080074155051B9E803E40A84C08C -:10174000E0FA84C07504B024E60A59583D4000739D -:10175000B58A86A50024EF8886A500E60C81CE1008 -:1017600004897638EBA00008040C0109050D020A73 -:10177000060E030B070F004080C02060A0E0105051 -:1017800090D03070B0F0E4D2E6D08AC825030003D0 -:10179000D8D1E32E8BAF4400888EAE00E4D8C0E8E9 -:1017A000048BD82E8A8766178AE08AC88686A900A5 -:1017B00032E0E4988B5E3E84E374548AC18B4E26FB -:1017C000F6C504740CA808740580E1BFEB0380C95A -:1017D00040F6C508740CA802740580E17FEB038015 -:1017E000C980884E268BF08A86A500F6C1FD740854 -:1017F000A806741924F9EB0FA8067511F6C5017532 -:10180000040C04EB020C028886A500E60C8BC6844F -:10181000E775098A86AE00243FE6D2C3C686BA00C1 -:1018200001B00EE81CF8F74638000274E6837E2EFD -:101830000672E08A86A9008AE08686AA008AC832F3 -:10184000C480C90B22C1C0E4040AE0C45E048B7EDC -:101850002CB0FFAAB002AB26830703836E2E038948 -:101860007E2CF646382075AB834E3820B000E8D188 -:10187000F7EBA090E41224DFE61281E3FE9F895E7D -:1018800026836648F7EB7390F6C72075E7E4120CE1 -:1018900020E61232C0E6C6B083E6C680CF20895E5D -:1018A000268A86A5000C028886A500E60CEB7490BB -:1018B000F6C74075D3E4120C20E61232C0E6C6B07B -:1018C00081E6C680E7DF80CB01895E26B006E8713D -:1018D000F7908A86A50024F9E60C8886A500EB43DC -:1018E000E4D4E6D08BF825030003D8D1E32E8BAFE8 -:1018F00044008B5E26F6C76075B6F6C3C075D3BAD2 -:10190000C6008B4E1C8B461A3BC8731E014E2A2BF9 -:10191000C189461AC57600F36E8ED98976003D20BE -:1019200000723D8BC7243FE6D4C385C074398BC891 -:1019300001462AC57600F36E8ED983CB02895E26D6 -:10194000E8D9EDF6C70175398A86A50024F9E60CB9 -:101950008886A500F6C71075CAB002E8E4F6EBC3A6 -:10196000F6C70174EFEBBCF6C70174DC8A86A500EC -:10197000A802741181E3FFFE81CB0002895E26EB91 -:10198000C78A86A50024FB0C02E60C8886A500EB1E -:101990009290FDF7DF7FFEFBEFBF0004000405041B -:1019A00005040104000405040504060406040504F6 -:1019B00005040604060405040504020400040504E5 -:1019C00005040104000405040504060406040504D6 -:1019D00005040604060405040504070407040504B9 -:1019E00005040704070405040504060406040504A9 -:1019F0000504060406040504050407040704050499 -:101A00000504070407040504050406040604050488 -:101A10000504060406040504050403040004050483 -:101A20000504010400040504050406040604050475 -:101A30000504060406040504050402040004050464 -:101A40000504010400040504050406040604050455 -:101A50000504060406040504050407040704050438 -:101A60000504070407040504050406040604050428 -:101A70000504060406040504050407040704050418 -:101A80000504070407040504050406040604050408 -:101A90000504060406040504050433DB8AD88A8796 -:101AA0006C12E6FEC1E302E4CEA8047509A8027434 -:101AB00003E92CFEF9C35053E8CBFC5B58A8027431 -:101AC00003E91CFEF8C333DB8AD88A876C12E6FE72 -:101AD000C1E302E9D0FB9A1AC61A00000200040012 -:101AE00002000600020004000200080002000400D8 -:101AF000020006000200040002000A0002000400C6 -:101B000002000600020004000200080002000400B7 -:101B1000020006000200040002000C0002000400A3 -:101B20000200060002000400020008000200040097 -:101B3000020006000200040002000A000200040085 -:101B40000200060002000400020008000200040077 -:101B5000020006000200040002000E000200040061 -:101B60000200060002000400020008000200040057 -:101B7000020006000200040002000A000200040045 -:101B80000200060002000400020008000200040037 -:101B9000020006000200040002000C000200040023 -:101BA0000200060002000400020008000200040017 -:101BB000020006000200040002000A000200040005 -:101BC00002000600020004000200080002000400F7 -:101BD00002000600020004000200C390DA1494150B -:101BE0005C13E613DA1BDA1BE613DA1B8B94641220 -:101BF000C1E604A80174355033C08AC2E6FEE4A0F1 -:101C000085C074278BD82E8A9FDA1A52562E8BA83D -:101C100044008B5628ECA801750D8886AD00240E73 -:101C20008AD82EFF97DC1B5E5AEBCD58A80274367B -:101C300083C61033C08AC6E6FEE4A085C074278B35 -:101C4000D82E8A9FDA1A52562E8BA844008B56281B -:101C5000ECA801750D8886AD00240E8AD82EFF975A -:101C6000DC1B5E5AEBCDC39032E48BD88BD02E8A2E -:101C70009F9A192E2297921956528AC3240303C69B -:101C800080E304D0EB2EFF97D61A585EA955007555 -:101C9000D9C3601E062BC08ED8A15C12E6FEE400FC -:101CA00022C4740833F6E8BFFFEBEE90E40407E4C7 -:101CB000041FB80080BA22FFEF61CF90601E062B90 -:101CC000C08ED8A15E12E6FEE40022C47408BE04F1 -:101CD00000E894FFEBEDE40407E4041FB80080BAC9 -:101CE00022FFEF61CF90601E062BC08ED8A15C1240 -:101CF000E6FEE40022C4741833F6E86BFFA160121C -:101D0000E6FEE40022C474E5BE0800E85AFFEBDDFD -:101D1000A16012E6FEE40022C475EDE40407E404C9 -:101D2000A15C12E6FEE4041FE404B80080BA22FFBE -:101D3000EF61CF90601E062BC08ED8A15E12E6FE2A -:101D4000E40022C47419BE0400E81CFFA16212E67C -:101D5000FEE40022C474E4BE0C00E80BFFEBDCA13F -:101D60006212E6FEE40022C475EDE40407E404A177 -:101D70005E12E6FEE4041FE404B80080BA22FFEF1E -:101D800061CF601E062BC08ED8A15C12E6FEE480F7 -:101D900084C4740833F6E853FEEBEE90B80080BAC2 -:101DA00022FFEF071F61CF90601E062BC08ED8A1C7 -:101DB0005E12E6FEE48084C47408BE0200E82CFED5 -:101DC000EBEDB80080BA22FFEF071F61CF90601ED5 -:101DD000062BC08ED8A16012E6FEE48084C474088D -:101DE000BE0400E806FEEBEDB80080BA22FFEF0764 -:101DF0001F61CF90601E062BC08ED8A16212E6FE36 -:101E0000E48084C47408BE0600E8E0FDEBEDB80091 -:101E100080BA22FFEF071F61CF90601E062BC08E95 -:101E2000D8A15C12E6FEE40022C4741833F6E83749 -:101E3000FEA16012E6FEE48084C474E5BE0400E8FE -:101E4000AAFDEBDDA16012E6FEE48084C475EDA17D -:101E50005C12E6FEE40407E4041FB80080BA22FF27 -:101E6000EF61CF90601E062BC08ED8A15E12E6FEF9 -:101E7000E40022C47419BE0400E8ECFDA16212E67D -:101E8000FEE48084C474E4BE0600E85FFDEBDCA1E0 -:101E90006212E6FEE48084C475EDA15E12E6FEE403 -:101EA0000407E4041FB80080BA22FFEF61CF601E70 -:101EB000062BC08ED8A15C12E6FEE48084C47418A0 -:101EC00033F6E827FDA16012E6FEE40022C474E5C3 -:101ED000BE0800E892FDEBDDA16012E6FEE4002200 -:101EE000C475EDE40407E4041FB80080BA22FFEFD4 -:101EF00061CF601E062BC08ED8A15E12E6FEE48084 -:101F000084C47419BE0200E8E2FCA16212E6FEE499 -:101F10000022C474E4BE0C00E84DFDEBDCA16212AB -:101F2000E6FEE40022C475EDE40407E4041FB800F3 -:101F300080BA22FFEF61CF90601E062BC08ED8A121 -:101F40005C12E6FEE48084C4741833F6E89DFCA1BC -:101F50006012E6FEE48084C474E5BE0400E88CFCF4 -:101F6000EBDDA16012E6FEE48084C475ED071FB8C6 -:101F70000080BA22FFEF61CF601E062BC08ED8A171 -:101F80005E12E6FEE48084C47419BE0200E85CFCC4 -:101F9000A16212E6FEE48084C474E4BE0600E84B4D -:101FA000FCEBDCA16212E6FEE48084C475ED071F41 -:101FB000B80080BA22FFEF61CF90601E062BC08E62 -:101FC000D8902AC0E6FEE4CEA801741433DBE8D52D -:101FD000F6EBEF90B80080BA22FFEF071F61CF90B9 -:101FE000F60605010175EDB001E6FEE4CEA8017428 -:101FF000E3BB0400E8AFF6EBC990601E062BC08E71 -:10200000D890FB90FA2AC0E6FEE4CEA802741333FF -:10201000DBE8CCF8EBECB80080BA22FFEF071F61D9 -:10202000CF90A80474F033DBE85BF7EBD590601E2B -:10203000062BC08ED890FB90FAB001E6FEE4CEA845 -:10204000027415BB0400E897F8EBEB90B80080BA77 -:1020500022FFEF071F61CF90A80474F0BB0400E8D3 -:1020600024F7EBD26A001FC6069312099C0EE86B98 -:10207000F2906A001FC6069312299C0EE85DF2904A -:10208000722072207220CE1D921CE61C1A1E722035 -:10209000821DAE1E381F7220821D72207220381FD2 -:1020A000722072207220F41DBC1C341D641E72202C -:1020B000A81DF21E781F7220A81D72207220781FA2 -:1020C000FCB940008CCBB864202BFFAB93AB93E200 -:1020D000FAC7064C00A811833E4412007520C706BB -:1020E0003C00084BC7063000BA1FC7063400FA1F71 -:1020F000F6060501017506C70638002E20C3C7067F -:102100003C00564B33DB8A1E5412C1E302021E56BA -:10211000122E8B878020A330008A1E5512C1E30245 -:10212000021E57122E8B87A020A33400C38B869EDD -:1021300000E6FE86C4E6D0C38B869E00E6FE33D260 -:102140008AD4C351B91027E40A909084C07405E280 -:10215000F659F9C359F8C384C0781E518AE88AC871 -:10216000B80100D3E0098698003AAEA00059751076 -:10217000E8A9E5834E2602F9C39889869800EBF01A -:10218000F8C384C07812518AE08AC8B80100D3E04D -:1021900059F7D021869800C3C78698000000C383F2 -:1021A000C2048A86A6000C04EE83EA04C3E893FF07 -:1021B0007204B082E60AC38B4626A8FD74118A8693 -:1021C000A500A806740824F98886A500E60CC3F6C5 -:1021D000C401740A8A86A50024FB0C02EB0CA80239 -:1021E000750F8A86A50024FD0C043A86A50075D8D3 -:1021F000C38A86A500EBCFE4D833DB8AD8C0EB04D2 -:102200002E8A9F6617889EA9008B5E2680E33FF684 -:10221000C7047407A810750380CB40F6C70874077D -:10222000A880750380CB40885E268A86A500F6C309 -:10223000FD740DA806740824F98886A500E60CC371 -:10224000F6C70174040C02EBF0F6C30275E90C0446 -:10225000EBE7C404C4048504590448044104C303DF -:10226000820341038202570241028201410182003E -:1022700041004E02AD0157012D002B002700210027 -:102280001600F404F404A3046F045B045104F40383 -:10229000A3035103A3026D025102A3015101A30044 -:1022A00051006202D9016D01380036003100290069 -:1022B0001B005157BF0200EB0F905156BF0100EBBE -:1022C00007905156BF0300903C197602B017988BC7 -:1022D000F08A82C4002AE48BF083FE187346D1E6AC -:1022E0002E8B8C5222F74638800074052E8B8C8200 -:1022F00022F7C7020074123B8E9400740C898E94EE -:10230000008AC5E6EC8AC1E6E4F7C7010074123B17 -:102310008E9600740C898E96008AC5E6F88AC1E60E -:10232000F05E59C377068B8E8E00EBC58B8E9000C6 -:10233000EBBFD503F6003E0010000400CA043301D1 -:102340004D00140005000103050709000102030404 -:1023500080841E00A02526000000608BF033FF2E35 -:10236000A150232E8B165223BB3223F74638800010 -:10237000740C2EA154232E8B165623BB3C23B90577 -:10238000002E3B31730A4747E2F7B8FFFFEB1D9081 -:10239000D1EF2E8A8D46232AEDD1EAD1D8E2FAF781 -:1023A000F6050200C1E8022E8AA54B232EA358236E -:1023B000612EA15823C3080020008000000260099C -:1023C0000800200080000002000800000100020058 -:1023D0000300040052565785C074053D0109760379 -:1023E000B80109BF5B01F7463880007403BFB20132 -:1023F00033F62E3B84B62376044646EBF5F7E72EFC -:102400008BBCC02303C783D200D1E7F7F72E8AA481 -:10241000CA235F5E5AC3E43E80BEC30003750CF757 -:10242000467A200074050C80E63EC3247FE63EC356 -:1024300024038886C3008AE0E41024FC0AC4E61062 -:10244000808EA10042E8CEFFC390568BF083E60752 -:10245000D1E62EFFA458249068246C2470247424A0 -:102460007824872487248724B400EB0EB4C0EB0AB9 -:10247000B440EB06B420EB02B4A0E410241F0AC45D -:10248000E610808EA100425EC3903C0277128AE083 -:10249000E41024F3C0E4020AC4E610808EA10042D6 -:1024A000C3908B5E3884C0741F3C02742083CB08B9 -:1024B0008B462E3B463C770CE888FC7207B024E63E -:1024C0000A83CB10895E38C383E3F7EBF7F7C310B9 -:1024D0000074F5E86DFC72EC8A86C000E638B02323 -:1024E000E60AEBE08B5E388B462E3B463CE4D87721 -:1024F0000B24FE80CB12E6D8895E38C30C0180CB5A -:1025000002EBF35033DBC1E804250F0F8AD82E8A83 -:102510008766178ADC2E8AA7661709463E58C3507D -:1025200033DBC1E804250F0F8AD82E8A8766178A05 -:10253000DC2E8AA76617F7D021463E58C38B463E4D -:1025400033DB8AD80ADC2E8A877617E62C8AE0E409 -:102550002A240F0AC4E62A8A86A50084E4750DA8F9 -:10256000807411247F8886A500E60CC3A8807504BA -:102570000C80EBF1C31E6033C933D233F68ED98D94 -:10258000BEFD00578B0584C074168BD1428BFE4F65 -:10259000780938A3E40074084F79F788A2E400466C -:1025A0005F83C7094183F91072D989B6860089967D -:1025B0008400611FC353C7466600008B4664A94070 -:1025C00000740DB300A980007402B37F889EC1001F -:1025D00032DBA90200740380CB40A9004074038061 -:1025E000CB02A90080740380CB01A9301E74038044 -:1025F000CBBCA90020740380CB08A904017403801C -:10260000CB10A90800740380CB20889EC2005BC356 -:102610000651575016078DBEC400B91F0033C0AA1B -:1026200040E2FC8B86920089868E00898690005855 -:102630005F5907C3E4D8C0E80453250F008BD82E98 -:102640008A8766178886A9005AC30886AC00C686A2 -:10265000BA0001B00EE8EAE9C3AD36A3B413AD3653 -:10266000A3B613AD36A3B81383E90636F706B6133F -:102670000F00C38A4626F74648800074020C108873 -:1026800086BD0032C0837E1A00750E8B5E4043808B -:10269000E3FE3B5E0875020C01837E3A00750D1E59 -:1026A000C55E148B1F1F85DB75020C02F7463810C0 -:1026B0000074020C048B5E7AF7C3020074020C08EB -:1026C000F7C3040074020C10F7C3080074020C2056 -:1026D000F7C3400074020C408886BF00C3906A00B4 -:1026E0001FC60693120D9C0EE8F1EB90B002E6DADD -:1026F000F8C333C0E6DAF8C3B001E6D8F8C333C094 -:10270000E6D8F8C3B0FFE84EFAE8A1FAF8C3AC493E -:10271000E8AFFBF8C390AC49E815FDF8C390AC49AD -:10272000E867FDF8C390AC49E81FFDF8C390AC49D9 -:10273000E634F8C3AC49E636F8C3AC493C02771F2F -:1027400084C0751DE41424EFE614E412243FE6125D -:10275000E416A8047409E8EAF97204B018E60AF865 -:10276000C38AE0E4140C10E614E4120CC0F6C401B1 -:102770007402247FE612F8C3AC49E825FDF8C39043 -:10278000B80040E87DFDE8B4FDE8A8FEB001E8B976 -:10279000FEF8C390B80040E885FDE8A0FDF8C390BE -:1027A000B80010E85DFDE894FDE888FEB008E899FF -:1027B000FEF8C390B80010E865FDE880FDF8C3900E -:1027C000B80080E83DFDE874FDE868FEB002E879F5 -:1027D000FEF8C390B80080E845FDE860FDF8C390BE -:1027E000B80020E81DFDE854FDE848FEB004E859B3 -:1027F000FEF8C390B80020E825FDE840FDF8C3903E -:10280000AC49E84814E43C24E70AC4E63CF8C39029 -:10281000B8FC3B89467CE43C0C18E63CF8C3E41267 -:102820000C02E612F8C3E41224FDEBF6E8B5FCF85E -:10283000C390836638FDF8C3AC49A8017406834E83 -:102840007A20EB0483667ADFE8CBFBF8C3908A86B4 -:10285000A5000C0224FB8886A500E60C814E26010B -:1028600020AC4932E489466E834E48084946F9C394 -:102870008A86A5000C0224FB8886A500E60C814E02 -:10288000260120ACB40AF6E4EBD8E8FA13E43C24C1 -:10289000F80AC4E63CF8C390AD4949894664A901E9 -:1028A00000741B8BD883E3FA751AA90400740FE433 -:1028B0003E0C02E63EB83844894662F8C390E43ED6 -:1028C00024FCEBEFE43E24FCE63EE8E8FCB8AA403A -:1028D000EBE6E86EF87205B018E60AF8C390AC496A -:1028E000E8CFF9F8C390AC49E8CFF9F8C390E868AD -:1028F000FD750632C0E6DAF8C3B002E6DA36A0B4F7 -:102900001324103410E8160136A1B413A901007481 -:1029100005E8FCFEEB0EA90200740432C0EB02B025 -:1029200001E8DEFE36A1B413E8B513E43C24F80A4E -:10293000C4E63C36A1B413C1E805250100E8FAFE5F -:1029400036A0B5132410E859FB32C0368A26B513D9 -:10295000F6C4047409FEC0F6C4087402FEC0E8DBC5 -:10296000FD36A1B613250F00E857F936A1B613C1FD -:10297000E804250300E8B8FA36A1B613C1E8052536 -:102980000200E805FB36A1B613F6C401750432C097 -:10299000EB0980E402D0ECB0022AC4E8ACFA36F6C7 -:1029A00006B713407405E883FEEB03E884FE36F6B1 -:1029B00006B713207405E865FEEB03E868FEF8C36C -:1029C000E4120C01E612F8C3E41224FEEBF6E41460 -:1029D00024F00C05E614E42A24F00C06E62AF8C3D9 -:1029E000E42A24F0E62AE41424F00C07E614F8C3E1 -:1029F000AD4949E864F989868E00F8C3AD4949E8D4 -:102A000058F989869000F8C3834E2604E8A8F7F8A1 -:102A1000C390836626FBE89EF7F8C390AC4984C058 -:102A2000750DE41024EFE610808EA10042F8C3E497 -:102A3000100C10EBF190AC493C02760232C0C0E0C1 -:102A400004A82074020C0824188AE0E41224E70A7F -:102A5000C4E612808EA10044F8C3AC498886C00049 -:102A6000F8C3AC49E63AF8C3AC4984C07408E41230 -:102A70000C04E612F8C3E41224FBEBF6AC49E8D6EA -:102A8000F67303E827F7F8C3E412A802740424FDE0 -:102A9000E612B8F000E887FA816626FFF3E857F7F8 -:102AA000E89AFAF8C390B88000E857FA804E2708F1 -:102AB000E844F7E887FAF8C3B88000E861FA81666D -:102AC00026FFF7E831F7E874FAF8C390B81000E889 -:102AD00031FA804E2704E81EF7E861FAF8C3B8100F -:102AE00000E83BFA816626FFFBE80BF7E84EFAF8B0 -:102AF000C39033C0AC493C017304B001EB063C0CFD -:102B00007602B00C89461CF8C390814E2600208ABC -:102B100086A5000C0224FB8886A500E60C834E26C1 -:102B200001F8C390814E2600408A86A5000C0288D9 -:102B300086A500E60CF8C390AC4950E805F658723B -:102B400008E638B023E60AF8C3F9C390AC50ADE804 -:102B500082F85AF6C201741239869600740C89867E -:102B60009600E6F086E0E6F886E0F6C202741039D8 -:102B7000869400740A89869400E6E486E0E6EC8395 -:102B8000E903C390E4168886BC00E8E6FA33DBE488 -:102B90000CA806740380CB01A810740380CB02A894 -:102BA00080740380CB04E4128AE024180AD8E4DAA3 -:102BB000F6C4027407A840750380CB20A8027509EB -:102BC000E42AA80F740380CB40F74638020074094A -:102BD000E4D8A801750380CB80889EBE00FE86B431 -:102BE00000B00AE85CE4F8C3AC493C027441771FCA -:102BF00050E84FF558720C84C0740AB012E60A808F -:102C00004E3801F8C3B011E60A806638FEF8C38B6F -:102C1000463825FFF7894638A9000475E68A86A557 -:102C200000A81075DE0C108886A500E60CF8C3819C -:102C30004E3800088A86A500A81074C724EFEBE779 -:102C4000AD49493C0172113C0C770D508AE0E41407 -:102C500025F00F0AC4E614588AC484C07402E64200 -:102C6000F8C3E8CFF9FE86B900B00EE8D4E3F8C3A4 -:102C70003A86AF00741F8886AF008AE080C206B033 -:102C8000BFEE80EA028AC4EE8A86A80080C202EE05 -:102C900080EA068AC4C38B463E85C08A86A5007436 -:102CA00012A808750D0C088886A50080C202EE8067 -:102CB000EA02C3A80874FB24F7EBEC8B462684C019 -:102CC00074168A86A500A802740D24FD8886A500C6 -:102CD00083C202EE83EA02C38A86A500A80275F7C2 -:102CE0000C02EBE85283C20CECC0E8048886A90011 -:102CF0008B5E2680E33FF6C7047407A8087503803F -:102D0000CB40F6C7087407A802750380CB80885EA5 -:102D1000268A86A50084DB7410A802740A24FD8824 -:102D200086A50083EA0AEE5AC3A80275FA0C02EBE4 -:102D3000EE90FFFF00480030BA20C41A00180012BD -:102D4000000C0006000300028001C000600030009B -:102D50001800CD0100018000100010000E000C00D2 -:102D6000080000000000060004000300020001004B -:102D70005251563C1E7747988BF08A82C40032E449 -:102D800083FE18743D83FE19743E83FE1E772FD197 -:102D9000E62E8B8C322D3B8E94007422898E94000B -:102DA00083C2068A86A8008AE00C80EE83EA068A3F -:102DB000C1EE83C2028AC5EE83C2048AC4EE5E59A4 -:102DC0005AC38B8E8E00EBCE8B8E9000EBC8525187 -:102DD0003D05007703B805008BC8BA0200B800D0E3 -:102DE000F7F1050100D1E8595AC38B467AA820743F -:102DF0000B80BEC3000375040C01EB0224FE894660 -:102E00007AC324038886C3008AA6A8008ADC80E4EB -:102E1000FC0AC43AC3740B8886A80083C206EE83FA -:102E2000EA06E8C5FFC30008183828903C04772359 -:102E300032E48BD82E8A87262E8AA6A8008ADC80C8 -:102E4000E4C70AC43AC3740B8886A80083C206EE9E -:102E500083EA06C384C07402B0048AA6A8008ADC90 -:102E600080E4FB0AC43AC3740B8886A80083C206B8 -:102E7000EE83EA06C3908B5E3884C074343C0274DF -:102E80003B8A86AF000C04E8E6FD8B462E3B463CB1 -:102E9000771BF7C30004751581CB000483C2028A37 -:102EA00086A50024FA8886A500EE83EA02895E38AA -:102EB000C38A86AF0024FBE8B6FDEBF1F7C3100030 -:102EC00074EFEBED83C20CEC83EA0CC0E804888657 -:102ED000A900C3908A86A7000C018886A7008BDA18 -:102EE00080C208EE8BD3F8C38A86A70024FEEBEAE3 -:102EF0008A86A7000C02EBE28A86A70024FDEBDAA3 -:102F0000B0FFE852F2E897F2F8C3AC49E861FEF886 -:102F1000C390AC49E8EBFEF8C390AC49E835FFF844 -:102F2000C390AC49E805FFF8C3905283C206B0BF16 -:102F3000EE5283C202AC49EE5A8A86A800EE5AF8D5 -:102F4000C3905283C206B0BFEE5283C206EBE69036 -:102F5000AC493C02770D84C0750B8A86AF0024FD16 -:102F6000E80DFDF8C3508A86AF000C02E801FD5B56 -:102F700083C2088A86A700F6C301740C24DF888602 -:102F8000A700EE83EA08F8C30C20EBF2AC49E8E5B1 -:102F9000FEF8C390B80040E869F5E8F9FCE824FFC2 -:102FA000B001E8A5F6F8C390B80040E871F5E8E58F -:102FB000FCF8C390B80010E849F5E8D9FCE804FF34 -:102FC000B008E885F6F8C390B80010E851F5E8C5F8 -:102FD000FCF8C390B80080E829F5E8B9FCE8E4FE05 -:102FE000B002E865F6F8C390B80080E831F5E8A5CE -:102FF000FCF8C390B80020E809F5E899FCE8C4FEA5 -:10300000B004E845F6F8C390B80020E811F5E8856B -:10301000FCF8C390AC49E8340CF8C390B8FC3B8989 -:10302000467CF8C38A86AF000C80E843FCF8C39066 -:103030008A86AF00247FEBF28A86AF000C40E82F2F -:10304000FCF8C3908A86AF0024BFEBF2AC49A8011C -:103050007407834E7A20EB059083667ADFE88AFD59 -:10306000F8C383C2068A86A8000C408886A800EEB2 -:1030700083EA06AC4932E489466E834E2601834ECC -:103080004808B006E8BBDF4946F9C39083C2068A08 -:1030900086A8000C408886A800EE83EA06ACB40A35 -:1030A000F6E4EBD0E8E00BF8C390AD4949894664FB -:1030B000A9010074198BD883E3FA750AA904007476 -:1030C0000DB8E23FEB0BE8ECF4B8AA40EB03B838DC -:1030D00044894662F8C38A86AF00A802740A24FDB8 -:1030E000E88DFB0C02E888FBF8C3AC49E881FCF8EA -:1030F000C390AC49E879FCF8C390E85CF57505E845 -:10310000E6FDF8C3E8CDFD36A0B41324103410E872 -:10311000260136A1B413A901007405E8FEFEEB0EEA -:10312000A90200740432C0EB02B001E8E8FE36A147 -:10313000B413E8AB0B36A1B413C1E805250100E8D0 -:103140000CFF36A0B5132410E82BFD32C0368A26BA -:10315000B513F6C4047409FEC0F6C4087402FEC0B8 -:10316000E8EFFD36A1B613250F00E803FC36A1B643 -:1031700013C1E804250300E888FC36A1B613C1E8B2 -:1031800005250200E8CDFC36A1B613F6C40175048E -:1031900032C0EB0980E402D0ECB0022AC4E88CFC17 -:1031A00036F606B713407405E88DFEEB03E894FE8F -:1031B00036F606B713207405E869FEEB03E870FEE7 -:1031C000F8C3F8C38B4638A9040075230D040089A1 -:1031D000463883C2088B462E3B463C7314834E38D8 -:1031E000108A86A70024FE8886A700EE83EA08F8E6 -:1031F000C38A86A7000C01EBEE908B4638A9040029 -:10320000740625FBFF894638F8C3AD4949E8BEFB83 -:1032100089868E00F8C3AD4949E8B2FB89869000E3 -:10322000F8C3834E2604E892FAF8C390836626FB1F -:10323000E888FAF8C390AC4984C07507808EA30073 -:1032400004F8C380A6A300FBF8C3AC4983C2083CC2 -:1032500002760232C03C017412770B8A86A70024E2 -:10326000EF8886A700EE83EA08F8C38A86A7000CD9 -:1032700010EBEE905283C206B0BFEE5283C204AC94 -:1032800049EE5A8A86A800EE5AF8C3905283C206C5 -:10329000B0BFEE5283C208EBE690AC49F8C3AC492C -:1032A000E8B4EE7303E8F7EEF8C38A86AF00247F34 -:1032B000E8BDF9B8F000E866F2816626FFF3E8237E -:1032C000FAE8D2F9F8C3B88000E837F2804E270850 -:1032D000E811FAE8C0F9F8C3B88000E841F2816665 -:1032E00026FFF7E8FEF9E8ADF9F8C390B81000E85A -:1032F00011F2804E2704E8EBF9E89AF9F8C3B81008 -:1033000000E8FFF1816626FFFBE8D8F9F8C3AC4975 -:10331000F8C383C2068A86A8000C408886A800EEFF -:1033200083EA06F8C39083C2068A86A80024BFEB0E -:10333000EA90AC498AE080C20AEC80EA0AA82074CC -:10334000058AC4EEF8C30651578B4E24E3344989ED -:103350004E24FF461A8E46028B7E228AC4AA897E9C -:10336000228B462624FD89462675298A86A500A833 -:1033700002752180C2020C028886A500EE80EA0256 -:10338000EB12C47E003B7E1E760A4F268825897E7E -:1033900000FF461A5F5907F8C390ACAD83E9038577 -:1033A000C074053D00207205B8FFFFEB03C1E003C8 -:1033B0003B8694007426898694008BD85283C2067B -:1033C0008A86A8008AE00C80EE83EA068AC3EE8330 -:1033D000C2028AC7EE83C2048AC4EE5AF8C3B08818 -:1033E0008886BC00E88CF233DB8A86A500A80274CC -:1033F0000380CB01A805740380CB02A80874038066 -:10340000CB04F686A70010740380CB108A86A9002F -:10341000F6C304750A83C20CEC83EA0CC0E8048A84 -:10342000E08A86AF00A8807408F6C401750380CBDB -:1034300020F686A70002750AF74638040074038058 -:10344000CB40889EBE00FE86B400B00AE8F3DBF8ED -:10345000C3FE86B400B00AE8E8DBF8C3AC493C021E -:103460007437771084C07406804E3801F8C38066C4 -:1034700038FEF8C38B463825FFF7894638A9000483 -:1034800075EA8A86A500A80175E20C0583C2028848 -:1034900086A500EE83EA02F8C3814E3800088A86CA -:1034A000A500A80174C624FAEBE2AD4949F8C3901F -:1034B000E811FAFE86B900B00EE886DBF8C3B0FF6B -:1034C000E8BFECF8C39083667AFBB000E873DBF8E2 -:1034D000C390AC49E853D9721136881E1A0136A040 -:1034E0008E120AC352BA0001EE5AF8C3AC4932E454 -:1034F00036A38612050600368B1E88122BD8368915 -:103500001E8A12F8C390AD8BD8AD83E90403C32B98 -:103510004676894678F7467A0200740A83667AFD11 -:10352000B80000E81CDBF8C3061607AC49250F00FD -:103530006BC0098DBEFD0003F8AC49250F00AA85BC -:10354000C074082BC8518BC8F3A459E827F0E8448D -:103550000307F8C333C0AC4936A3B21336A3B01384 -:10356000F8C383667AEFE82C03F8C390834E7A1091 -:10357000EBF4E89BF0F8C390AD3C19770E3C19775B -:103580000A8BF881E7FF0088A6C400F8C390834E39 -:103590002620AC4932E4D1E08BD8C1E30203C389D1 -:1035A000466E834E4804B006E897DA4946F9C39060 -:1035B000FE86B300B00AE889DAF8C39033C0AC499C -:1035C0006BC00A89868A00F8C390AC4932E43D0A90 -:1035D000007705B80A00EB083D5A007203B85A009C -:1035E00051F7D80564008BC88B4644F7E1B96400F5 -:1035F000F7F189464659F8C3AC49E885EBF8C39022 -:10360000AC4984C07507816638FFFDF8C3814E3828 -:103610000002F74638400075088A86A9008886AA05 -:1036200000F8C3905156E87F0C5E59F8C390FE86AF -:10363000B600B00AE80BDAF8C390FE86B700B00A0D -:10364000E8FFD9F8C390FE86B800B00AE8F3D9F8CD -:10365000C39000905155AC2EA2523633C9AD8BF9B0 -:10366000C1E705A9010074232E8BAD4400837E08B9 -:103670000074182E803E523601740960B004E8BB15 -:103680000C61EB0760B0FBE8EC0C614747D1E875D3 -:10369000D24183F90472C65D5983E905F746384083 -:1036A000007405E887EAF8C3E88DEAF8C39036C6E7 -:1036B00006C81301F8C333C0AC4936A38012AC4925 -:1036C000362B068812F7D836A38212F8C390DE266E -:1036D000DE26EC26F226F826FE2604270E271627DD -:1036E0001E2726272E273427BE34C634D2343A2745 -:1036F000782780279427A027B427C027D427E0273E -:10370000F42700281028EC34DE261E2826282C2832 -:10371000322838284E288A28063528359828BE2889 -:10372000D228DE28E628543562356C35EE28C029CB -:10373000C829CE29E02972357835F029FC298E3543 -:10374000082A122A1C2AB035362ABC355A2A622A7F -:10375000682ACA357C2AF835882AA62AB82ACC2AAB -:10376000DE2AF22A00360A2B242B2436382B4C2B47 -:10377000842B2E363A3646365436E82BAE36402C5D -:10378000622CB6367028DE26DE26D42EE82EF02EE9 -:10379000F82E002F0A2F122F1A2F222F2A2F422FF6 -:1037A000BE34C634D234502F8C2F942FA82FB42F70 -:1037B000C82FD42FE82FF42F083014301C30EC34ED -:1037C000DE2624303030383044304C306230A43083 -:1037D00006352835AA30CE30D630EA30F2305435AE -:1037E00062356C35FA30C231C231C431FA317235CA -:1037F00078350A3216328E3522322C323632B035D6 -:103800004A32BC3574328C329A32CA359E32F8351F -:10381000AA32C632D832EC32FE320E3300361233C0 -:103820002633243632339A33DE332E363A36463652 -:1038300054365C34AE36AA34B034B6368C30E32815 -:10384000F7463840007532E8E3E833C0AC493D5BE9 -:103850000077198BD8D1E32EFF97CE36720B85C92E -:1038600075E88B4648E81A0CC34E41C36A001FC670 -:103870000693120C9C0EE863DAE8BCE833C0AC494E -:103880003D5B0077E78BD8D1E32EFF97863772D95F -:1038900085C975E8C3F7467A1000750F83BE8400AA -:1038A000007408B8483A89868000C381BE8000EC65 -:1038B0003C74F783BE8800007505B8EC3CEBE7F775 -:1038C000467A080075401E608B8E88003B4E7477E8 -:1038D000333B4E78772EC47E108BDF26033D47475F -:1038E00033C08ED88DB6F4008BC1F7467A010075CF -:1038F0001DF3A4260107294678014676294674B0AF -:103900000CE83ED7611FC78688000000EBACE3E3FC -:103910005090AC247FAAE2FA58EBD8908B8E8800A6 -:10392000E3468B9E8A0085DB743EBA50FFED2B8602 -:1039300082003BC372378DB6F400C47E108BDF2645 -:10394000033D47478BC1161FF7467A01007524F3E4 -:10395000A4260107294678014676294674C7868839 -:10396000000000B00CE8DAD683667AF7C3B000E84E -:10397000D0D6C3E3DC50AC247FAAE2FA58EBD29055 -:103980001E6033C08ED88DB6FD008B8688008B9666 -:1039900084003A0475108BDE468BC88DBEF400F3AC -:1039A000A674668BF39083C6094A75E68DB6FD0052 -:1039B0008B9684003A0473108BDE468BC88DBEF460 -:1039C00000F3A674768BF39083C6094A75E68DB62C -:1039D000F400ACF7467A01007402247F1EC55E1025 -:1039E0008B37884002468937FF4E78FF4676FF4E78 -:1039F000741F8B8E880049898E8800E3438DB6F44E -:103A0000008BFE46F3A4E97DFFC576108B1C85DB99 -:103A1000740803F383C60383E6FE8B8684002BC2FF -:103A2000B48089044646C7040000897610834E7A24 -:103A300004C78688000000611FF9C333C0611FC33B -:103A4000B08084C0611FC3908B4E782B8E88007627 -:103A50002789B68C008B5E743BCB72028BCB3BC844 -:103A600072028BC88BC1E34433D28EC28BD183BE2A -:103A70008800007406E98E0033C0C38B5E10031FFC -:103A8000434352F7467A0100752AAC8DBEE4008BA1 -:103A90008E8600F2AE74348807434A75ED588B5E0B -:103AA0001001072946780146762946748BC62B8675 -:103AB0008C00C390AC8DBEE4008B8E8600F2AE7499 -:103AC0000A247F8807434A75EBEBD28886F400C747 -:103AD0008688000100582BC2740E8B5E10010729E6 -:103AE000467801467629467440E894FE72BE4A75CF -:103AF0001583BE8A000074B4BA50FFED8986820037 -:103B0000834E7A08EBA68DBEF40003BE8800A4FFA6 -:103B1000868800E86AFE729479064A748FE95BFF32 -:103B20004A74CEEBE19050E811CC8B467439467262 -:103B300074271E565133C9C5760CAD74107809032D -:103B4000C805010024FE03F03B761076ED294E7681 -:103B5000014E78E837CC595E1F58C390C47E1026BA -:103B60008B1D83C30326891D4B03FBAB91AAB803AE -:103B700000294678014676294674C390C47E1026F3 -:103B80008B1D4326891D4303FBAAFF4E78FF467613 -:103B9000FF4E74C3E8E5FFC38081848582838687F6 -:103BA00050538ADC83E30ED1EB2E8A87983B08863C -:103BB000B000FE86B100B00AE887D45B58C3508AD3 -:103BC000C8B8FF00E895FF58C3908A86BB00E8ABF1 -:103BD000FFC3E8CBFFE8F2FFC390E8C3FFE8B4FF00 -:103BE000C39033C0E895FFC3B8FF0033C9E86CFF4A -:103BF000C390B8FF01B110E862FFC390C3FC3BE281 -:103C00003BF23BF23BFC3BE23BE83BE83BFC3BE26C -:103C10003BE83BE83BFC3BE23BE23BE23B00100085 -:103C20000000100000001000000010000000100054 -:103C3000000010000000100000001000000008004C -:103C40000000080000000800000008000051538B2D -:103C50004E3881E1FFEEA804740481C900018AE0B6 -:103C600080E4032418D0E40AC433DB8AD82E8B877F -:103C7000FD3B89467C2E0B8F1D3C894E38D1EB2EA7 -:103C80008AA73D3C5B59C3AC493C01721D74203C82 -:103C900003722374283C08722B74303C20723774F2 -:103CA0003ABBDA3B32E4895E7EC3BBA03BEBF5BB9B -:103CB000943BB401EBF0BBFC3BB402EBE9BBE23B51 -:103CC000B403EBE2BBBE3BB404EBDBBBCA3BAC4989 -:103CD0008886BB00EBCEBBD23BEBF3BBFC3BEBC41B -:103CE000A9040075D1A9080075DAEBD18B5E748B3D -:103CF0004E783BCB72028BCB3BC872028BC88BC118 -:103D0000E32CC47E108BDF26033D4747F7467A013C -:103D100000751CF7C70100740249A4D1E9F3A5732B -:103D200001A4260107294678014676294674C35026 -:103D300053BB7F7FF7C70100740549AC22C3AAD1EA -:103D4000E9E31D9CAD23C3AB497414AD23C3AB4958 -:103D5000740DAD23C3AB497406AD23C3ABE2E59D3F -:103D60007304AC22C3AB5B58EBB8E8CEC98B5E38AA -:103D7000F7C310047501C3F7C340007405E8B8E346 -:103D8000EB03E8A8E3816638EFFBF6C310743CF65A -:103D9000C3027406E4D80C01E6D8F6C30474118398 -:103DA000C2088A86A7000C01EE8886A70083EA086D -:103DB000F6C308740FE88BE3720A8A86C000E638FF -:103DC000B023E60AF7C300047501C3F7C300087502 -:103DD000F98A86A500F6C340750DA81075EC0C1085 -:103DE0008886A500E60CC3A80175DF83C2020C0516 -:103DF000EE8886A500C3B000E847D2EB0FB002E81A -:103E0000900EEB08836638DF834E7A0233C08ED87B -:103E1000FAA0921240A292123C05721EC60692129D -:103E200000FBB001E86B0EFAA1260123062A01A8C7 -:103E3000017507E8E207E8610990B000E837D2FBB6 -:103E400085ED74B9FAF7467A460075C08B46783D21 -:103E50000A0072B08B4E7483F950729A836638DF11 -:103E6000C576148B463A85C07558AD85C0750FE888 -:103E7000F8FEF7467A08007493E8A0FAEB8E3B76DA -:103E8000047621B90200394E2E7705C7462E000070 -:103E9000568B762C897604C7040000464689762C1A -:103EA000294E2E5E85C07917F6C4107405FF567C26 -:103EB000EB03FF567E897614B00CE885D1EB86893A -:103EC000463AFF96800029463A897614B00CE8718C -:103ED000D1E971FF0000000000000000080410029A -:103EE00001200000000000000000000000000000B1 -:103EF00000000000808080808080808080808080C2 -:103F000080808080808080808080808080808080B1 -:103F100080808080808080808080808080808080A1 -:103F20008080808080808080808080808080808091 -:103F30008080808080C0C0C0C0C0C0C0C0C0C0C0C1 -:103F4000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C080B1 -:103F500080808000808080808080808080808080E1 -:103F60008080808080808080808080808080808051 -:103F70008080808080808080808080808080808041 -:103F80008080808080808080808080808080808031 -:103F90008080808080808080808080808080808021 -:103FA0008080808080808080808080808080808011 -:103FB0008080808080808080808080808080808001 -:103FC00080808080808080808080808080808080F1 -:103FD000808080804E417841D041F44106421842B1 -:103FE000C3908E46028B7E22897E6C806627FD8B75 -:103FF000562483FA0472E983EA028BD93BCA76021B -:104000008BCAB00A57518BFEF2AE8BC1595F751E39 -:1040100050402BC874062BD12BD9F3A4594B4A4AD4 -:10402000B00DAAA43BCA76028BCAE313EBD42BD9FA -:10403000F7C601007402A449D1E9F3A57301A4896C -:104040007E222B7E6C297E24017E1A8BCB807E26DD -:10405000027405806626FDC360B0FDE8180361C3E5 -:10406000C390E87C0272F990834E26208B466A89C1 -:10407000466E8B46480D040025BFFF894648B006B2 -:10408000E8BFCFC3897E222B7E6C017E1A297E2455 -:10409000807E26027405836626FDC360B0FDE8D5E8 -:1040A0000261C3908ABEC200EB24F7464840007507 -:1040B000B18E46028B7E22897E6C8B562483EA0A5F -:1040C000789E03D7806627FD33C08ABEC200E3B462 -:1040D0003BFA77B0AC49932E8A87D43E9322DF75A2 -:1040E00017AAE3A03BFA779CAC49932E8A87D43E6B -:1040F0009322DF7503AAEBD6F6C37F7505FF4666EC -:10410000EBDFF6C340750C8BD883EB08D1E32EFFB1 -:10411000A7D43FFF46662C20EBC785C0742C894688 -:104120006A834E4840897E222B7E6C017E1A297E4E -:1041300024807E26027408836626FDE8A301C360FE -:10414000B0FDE8310261E89801C3E957FF908B5E4A -:10415000664B7803895E66AA8B5E64F7C3002075A0 -:1041600003E940FFF7C3400074088A86C100AAE94A -:1041700032FFB83200EBA3908B5E66895E6883C322 -:104180000880E3F8895E668B5E6481E3001881FB3A -:104190000018742DAA85DB7425F746644000751855 -:1041A00081FB0010740C8B46662B4668C1E004E965 -:1041B00068FFB86400E962FF8A86C100AAAAE9E341 -:1041C000FE518B4E662B4E68B020F3AA59E9D4FEFF -:1041D0008B5E66895E688B5E64F7C324007410C7CB -:1041E00046660000F7C304007405B00DAAB00AAA21 -:1041F000EB489090AAF7466400407406B8D007E9EF -:1042000018FFE99FFE90AAF7466400807406B8D0B4 -:1042100007E906FFE98DFE908B5E66895E6885DBA7 -:10422000750C8B5E64F7C310007406E976FE8B5E36 -:1042300064F7C308007427B00AAAF7C32000751FEB -:10424000F7C300017503E95BFEF7C340007506B8CC -:104250006400E9C5FE8A86C100AAAAE946FEAAC78B -:1042600046660000F7C3000674F1F7C340007419F6 -:104270008A86C10081E3000681FB00047206760293 -:10428000AAAAAAAAAAAAE91BFE81E3000681FB004A -:1042900004720E7606B89600E97FFEB86400E979EC -:1042A000FE8B4668E973FE90368B0EDA1283F93284 -:1042B000731D1E0633C08ED88EC08D764CBFDC12A7 -:1042C00003F9A5A5A583C106890EDA12071FC3B09D -:1042D00008E86ECDC390836648FEE893C4E8C8FF43 -:1042E000C3F6462702750F9CFA837E1A0074098074 -:1042F0004E27019DF9C3F8C35052F7463840007469 -:104300001DE834DE83C20AECA840752783EA088AD8 -:1043100086A5000C028886A500EE5A58EBD1E80C61 -:10432000DE8A86A50024FB0C028886A500E60C5ACE -:1043300058EBBC804E27025A589DF8C30846269C6D -:10434000FA8A8EA500F7463840007514F6C1067447 -:1043500023E8D9DD8AC124F98886A500E60C9DC32F -:10436000F6C102740FE8D0DD83C2028AC124FD8841 -:1043700086A500EE9DC38B5E2622C3884626740167 -:10438000C3806627FD9CFA8A8EA500F74638400058 -:104390007516F6C104750FE893DD8AC124FD0C047F -:1043A0008886A500E60C9DC3F6C10275F9E888DD94 -:1043B00083C20AECA820750E83EA088AC10C028821 -:1043C00086A500EE9DC383EA0A33C98A4E1C8B463C -:1043D0001A3BC8731B014E2A2BC189461A1EC5768B -:1043E00000F36E1F89760083C2028A86A500EBCD9A -:1043F00085C0741201462A8BC81EC57600F36E1F55 -:10440000897600894E1AF6C701752380CB02895E32 -:1044100026E808C383C2028A86A50024FDEE8886AA -:10442000A500F6C7107505B002E816CC9DC383C27F -:10443000028A86A500EB86908BD18B46243BC876FA -:10444000028BC82BD12BC18BD9E322806627FD8E2E -:1044500046028B7E22F7C601007402A449D1E9F31B -:10446000A57301A4897E22894624015E1A8BCA8025 -:104470007E26027405806626FDC360B0FDE8F6FE68 -:1044800061C350E40A84C0750A8686A10084C074A2 -:104490000AE60A580C20894648F9C35824DF8946A1 -:1044A00048F8C390FBB002E8E807FAE82E01FBB039 -:1044B00001E8DE07FAB002E8BCCBFB85ED74E5FA53 -:1044C0008E5E0AFB90FA8B46488B7640A88C75DE90 -:1044D000A820741A50E855DC58E8A6FF7310B00203 -:1044E000E85FCBEBC99025FF008BC8EB3690A801A5 -:1044F00075224683E6FE3B76087479AD8AFCB3F0FC -:1045000022FB3AFB74E03ABEA000742EE8D2FD73A1 -:1045100077EB9B908AE024FC8846488B4E4AF6C491 -:1045200002741DE8BBFD7286E813F3897640E393BD -:10453000834E4803894E4AE974FF25FF0F8BC890CC -:104540008B86980085C0741A518A8EA000C0E90439 -:10455000BA0100D3E25923C2740803F1897640E915 -:1045600061FFFF5662E3F5834E4801894E4A897622 -:1045700040E93AFF814E2600108B46503B46467775 -:1045800003E852FDE927FF9088BEA000EBAC0A06C5 -:1045900090128AE0BA0601B004EEEC84C07512B045 -:1045A00004EE8AC4EE32E4A8807406C706841200C2 -:1045B0000088269012C30A0690128AE0BA0601EC1F -:1045C000A80175EDBA08018AC4EE32E4A88074E14E -:1045D000C7068412000088269012C39036F706247E -:1045E0000101007530368B0EDA1280F936732633EE -:1045F000C08EC08ED8BFDC1203F9B008E877CA8538 -:10460000ED740E8D764CA5A5A580C10680F9367295 -:10461000E9890EDA12C3C390F7062601010075F688 -:104620008B0E201385C975EE33C08EC08ED8BF2483 -:1046300013B93600B00AE83DCA85ED7506E91201E6 -:10464000E90A0133DB8A464C8AA6B300FECC780E19 -:1046500088A6B3000ADCB40AAB83E90276E28AA634 -:10466000B200FECC780E88A6B2000ADCB408AB8398 -:10467000E90276CC8AA6B100FECC78188ABEB000DA -:10468000750488A6B00088A6B1000ADC8AE7AB836F -:10469000E90276AC8AA6B400FECC781F88A6B400E6 -:1046A0000ADCB40BAB8A86BC008AA6BD00AB8B8645 -:1046B000BE00AB83E90676888A464C8AA6B600FE21 -:1046C000CC781988A6B6000ADCB40CABE8DBCBAB1F -:1046D0008B462AAB83E90676748A464C8AA6B700D5 -:1046E000FECC781988A6B7000ADCB40DABE8BACBCB -:1046F000AB8B4634AB83E90676538A464C8AA6B820 -:1047000000FECC781988A6B8000ADCB40EABA15024 -:1047100012ABA15212AB83E90676328A464C8AA6C6 -:10472000B500FECC781888A6B5000ADCB40FAB8BB8 -:10473000869A00AB8B869C00AB83E906760F84DB00 -:104740007503E9EFFEB00AE8F8C8E9E7FEB00AE849 -:10475000F0C8F7D983C1368BC10D800086C4A3226F -:10476000134141890E2013C3A184122BC17211A3DE -:104770008412BE2213D1E9F36F90890E2013F8C37F -:10478000F9C3C381EF6A1374F98BC70D800086C427 -:10479000A368134747893E6613C3F7062A01010041 -:1047A00075E08B0E6613E30780F92077D54949330E -:1047B000C08EC08ED8BF6A138BF703F983C6343B13 -:1047C000FE77C0B00EE8AEC885ED74B78A464C8A55 -:1047D000B6B900FECE781588B6B9008AA6A90080C1 -:1047E000CCC0AB84F67405B00EE856C88AB6BA00E1 -:1047F000FECE78CB8A9EA9008ABEAB008A563F8A3D -:10480000F332F70AB6AC00C686AC000022F2744B55 -:10481000F6C608740FB402F6C3087502B403AB8081 -:10482000E6F77437F6C601740FB400F6C3017502DB -:10483000B401AB80E6FE7423F6C602740FB404F62E -:10484000C3027502B405AB80E6FD740FF6C60474AE -:104850000AB406F6C3047502B407ABC686BA0000F4 -:10486000889EAB00E958FF90A184122BC17211A35E -:104870008412BE6813D1E9F36F90890E6613F8C3F2 -:10488000F9C3A1841241412BC17223A384128BC1AD -:10489000484832E40C8086C4EF9090909090BEDC43 -:1048A000124949D1E9F36F90890EDA12F8C3F9C3BE -:1048B0008AC88A464CB40183EB06EF9090909090A2 -:1048C000B80100EF90909090908AC1EF90909090F6 -:1048D00090E99700E9AC0033C08ED8891E8412C3DA -:1048E000368B1E8412FB90FAB00CE889C785ED74F4 -:1048F000E6C5760C83FB1472DBFB90FAAD85C078BD -:10490000AF74E28BFE03F8368B0E86123BC1770242 -:104910008BC883EB043BD977028BCB33C08A464CE0 -:10492000EF90909090908BC1EF90909090904180FC -:10493000E1FE2BD951D1E9F36F90598BC74024FE8A -:104940003BC674272BFE4E4E538B5E103BF3721307 -:10495000031F83C30380E3FEC7070000836E740256 -:10496000895E105B893C89760CEB8989760C3976F7 -:104970001077817208833C007403E977FFE80DBE6D -:10498000E962FF36891E8412B00CE8B5C633C08ECA -:10499000D8C3A184123D10007277BA04013B068887 -:1049A000127506C7067E1200008B0EDA12E30BE8C2 -:1049B000D0FE7257C7067E12FF7F8B0E2013E30BCB -:1049C000E8A5FD7246C7067E12FF7F8B0E6613E3D5 -:1049D0000BE894FE7235C7067E12FF7FA12801A95D -:1049E00001007503E8F9FE803E8D1200751DA1845B -:1049F000123D200076153B0682127609A17E123BFD -:104A0000068012720C800E901280C3B080FF167C5C -:104A100012C3800E901240C36A001FC6069312177D -:104A20009C0EE8B7C86A001FC6069312209C0EE8C9 -:104A3000AAC86A001FC6069312169C0EE89DC8906D -:104A4000BA0601ECA82075CAFB90FABA0401ED90F1 -:104A5000909090903A06941277BE33DB8AD8D1E3D7 -:104A60002E8BAF4400C47E0885FF74B9F6C4C075B0 -:104A70005532C0C1E00280E4F08BF0ED9090909050 -:104A80009085C074BB8BC84180E1FE0BC68B5E5025 -:104A90004B4B2BD9789CAB8BC1404001464ED1E9A2 -:104AA000F36D90895E50897E088B462680E4EF89FD -:104AB0004626F6C401750CF746480C007505B00291 -:104AC000E87FC5E97AFF86C48BC883E13F4180E176 -:104AD000FEE30A3C807209243FB4F0EBB0E960FFCA -:104AE000253F0033FF8EC7BF96128BF7D1E9F36DD8 -:104AF000908BC8E848EDE947FF906A001FC606930F -:104B0000121B9C0EE8D5C790601E0633C08ED88E4F -:104B1000C0BA0601ECA80474E1B006EEECA28C1257 -:104B2000A8407411A18812A38412C6068D1200E851 -:104B300060FEA08C12A8807403E804FFB80080BA5D -:104B400022FFEF071F61CF906A001FC60693121B5A -:104B50009C0EE887C790601E0633C08ED88EC0BA00 -:104B60000601ECA80474E1BA0801ECA28C12A8407A -:104B70007411A18812A38412C6068D1200E812FED9 -:104B8000A08C12A8807403E8B6FEB80080BA22FF99 -:104B9000EF071F61CF90EE86E0EE86E0EC86E0EC5A -:104BA00086E080E1FEF36C9080E1FEF36E900500FC -:104BB0007547A84B05007548A84B0500A348A84BAE -:104BC00005003549A84B06009848964B0600BA48A0 -:104BD000964B0600C348964B0600CB48964B060002 -:104BE0002049964B06002849964B06004E4A9C4B9E -:104BF00006007B4A9C4B05009E4AA24B0500EC4AEE -:104C0000A24B00001E06833E4412007409A0060158 -:104C100024303C30741A8CC88ED88EC0BBAE4B8BFF -:104C20000FE30D8B7F028B7704F3A483C306EBEFB6 -:104C3000071FC39033C0A33E01B90C01BE40018BD6 -:104C4000FE81C6B40F89048BC62BF13BC777F6A350 -:104C50003C01C3901E0660368B2E3E018B5E003BEE -:104C6000EB742B8B7602891C89770236A13C018973 -:104C7000460036892E3C018BEBFF4E0674088B6E86 -:104C800000FF4E0675F836892E3E018B66046107DB -:104C90001FC31E0660368B2E3E0198894606896624 -:104CA000043B6E0074108B6E00FF4E0675F836895B -:104CB0002E3E018B660461071FC3C3901E06609CD5 -:104CC000FA33ED8EDD8B2E3C0185ED743D8B4E006D -:104CD000890E3C018BCC8DA60A01561E06608966A2 -:104CE00004C746080F1AC7460601008B1E3E018501 -:104CF000DB741D8BC58707894600895E028BD889C6 -:104D00006F028BE19D61071FF8C39D61071FF9C307 -:104D1000892E3E01896E00896E0287E19D8BE1EB51 -:104D2000E4000D0A5465726D696E616C73207375D1 -:104D300070706F727465643A0D0A312920414E53C8 -:104D40004920636F6D70617469626C650D0A322968 -:104D500020577973652033300D0A506C6561736597 -:104D60002073656C6563743A20000D0A636F646597 -:104D7000207365676D656E743D000D0A4D6F6E6939 -:104D8000746F722076322E350A0D0A3E000D0A50DD -:104D90006172646F6E3F000D0A4E6F206164647231 -:104DA00065737320737065636966696564000D0AD5 -:104DB0003A000D0A004C6F633D000D0A4641544114 -:104DC0004C204552524F523D000D0A4D6F6E697492 -:104DD0006F7220636F6D6D616E64733A2D0D0A20E2 -:104DE0002020442C645B5B787878783A5D7878781A -:104DF000785D202D2064756D70206D656D6F727902 -:104E00000D0A2020204C2C6C5B5B787878783A5D1A -:104E1000787878785D202D2064756D702073696EC8 -:104E2000676C65206C696E650D0A202020452C6535 -:104E30005B5B787878783A5D787878785D202D209B -:104E400065646974206D656D6F72790D0A2020208C -:104E5000462C665B5B78787878205D787878785D2A -:104E6000202D2066696C6C206D656D6F72792070E5 -:104E70006172616772617068730D0A202020495B5E -:104E8000787878785D202020202020202020202D78 -:104E900020776F726420696E7075742066726F6D12 -:104EA00020706F72740D0A202020695B7878787802 -:104EB0005D202020202020202020202D20627974B9 -:104EC0006520696E7075742066726F6D20706F72E8 -:104ED000740D0A2020204F78787878207878202068 -:104EE000202020202020202D206F757470757420C4 -:104EF000776F726420746F20706F72740D0A2020B7 -:104F0000206F787878782078782020202020202042 -:104F100020202D206F75747075742062797465205F -:104F2000746F20706F72740D0A202020475B5B78CD -:104F30007878783A5D787878785D2020202D206721 -:104F40006F746F20616464726573730D0A20202092 -:104F5000575B5B787878783A5D787878785D202050 -:104F6000202D207761746368206120776F72640D53 -:104F70000A20202043202020202020202020202024 -:104F800020202020202D20696E7465727275707447 -:104F900073206F66660D0A202020532020202020D9 -:104FA00020202020202020202020202D20696E7409 -:104FB00065727275707473206F6E0D0A20202073F5 -:104FC00020202020202020202020202020202020E1 -:104FD0002D2073696E676C6520737465700D0A20EF -:104FE000202042787878782020202020202020203F -:104FF0002020202D20627265616B706F696E7420B5 -:105000007365740D0A20202062202020202020209B -:105010002020202020202020202D20627265616B1E -:10502000706F696E7420636C6561720D0A202020B8 -:10503000522020202020202020202020202020203E -:10504000202D207265737461727420627265616BC9 -:10505000706F696E740D0A2020207220202020209D -:1050600020202020202020202020202D2072656755 -:105070006973746572732061742062726B70740D51 -:105080000A202020582C78206E202020202020204C -:1050900020202020202D206578616D696E652063B9 -:1050A00068616E6E656C206E0D0A202020482C3FD2 -:1050B00020202020202020202020202020202D20E3 -:1050C00074686973206D657373616765001B5B327B -:1050D0004A1B5B313B3148414E5349205465726D48 -:1050E000696E616C0D0A0A001B5B4B001B5B4A007A -:1050F0001B5B324A1B5B313B3148001B5B44201B6E -:105100005B44001B5B313B373248001B5B003B00BC -:1051100048001B5B73001B5B75001B7A2B0B7F1B0E -:105120007A2E0C7F1B7A2D087F1B7A2C0A7F1B7A24 -:1051300022087F1A57797365203330205465726DC9 -:10514000696E616C0D0A001B54001B59001A001E89 -:105150000008200800001B3D0000001B46000D0059 -:105160003F4464456546664767486849694F6F43F1 -:1051700063537342625272577758784C6C3C60D4D8 -:1051800057D45750585058D659D659B459B4593C99 -:10519000603C606C57485726570657905790579871 -:1051A00057485F0C5F585F335F405FA057A057FEC2 -:1051B00059FE59DC57DC5788619861C061CC61D8D1 -:1051C00061F66102622262F8564A625862605920B2 -:1051D00020666C6167733D00202061783D002020CF -:1051E00062783D00202063783D00202064783D00F7 -:1051F000202063733D00202064733D0020206573F0 -:105200003D00202073733D00202064693D00202074 -:1052100073693D00202062703D00202073703D00C6 -:10522000202069703D00206368616E656C3D002040 -:105230002020207365673D002074695F7374723DA0 -:10524000002074695F746F733D002074695F6D6145 -:10525000783D002074695F6261733D002074695F6E -:1052600073697A3D002074695F7374663D00207431 -:10527000695F726F6F3D002074695F666C673D0007 -:105280002074695F746F743D002072695F70636E93 -:105290003D002072695F7374723D002072695F7314 -:1052A00074663D002072695F726F6F3D0020726905 -:1052B0005F6261733D002072695F73697A3D00200F -:1052C00072695F746F743D002072695F6D696E3D35 -:1052D000002072695F666C673D002072695F746FC1 -:1052E000733D002072695F7468723D002074685FCE -:1052F0007374663D002074685F7374723D0020749F -:10530000685F6261733D002074685F73697A3D0075 -:105310002074685F7472673D002074685F666C6714 -:105320003D002074685F636E743D002072685F7397 -:1053300074723D002072685F7374663D002072686D -:105340005F6261733D002072685F73697A3D00207F -:1053500072685F7370613D002072685F61736F3DBA -:10536000002072685F726F6F3D002072685F666C2C -:10537000673D00206D5F636172653D002070745F62 -:10538000666C6F3D002061735F666C6F3D0020723C -:105390006D5F666C6F3D00202020715F696E3D007F -:1053A0002020715F6F75743D0020715F6472616EC3 -:1053B0003D002020715F74696D3D00202020715FE9 -:1053C00066633D0020715F737461743D0020715FFE -:1053D000646174613D0020715F6D6F646D3D0020FC -:1053E00068616E645F6F3D002068616E645F623D5E -:1053F000002068616E645F653D002068616E645FD7 -:10540000693D0020206F706F73743D002020746927 -:105410006D656F3D0020637573746D313D002063D1 -:105420007573746D323D0020637573746D643D0057 -:10543000207478726174653D0020727872617465C1 -:105440003D002020635F6D61703D0020635F6164FB -:1054500064723D0020635F616973723D0020635F89 -:10546000787461673D0020635F646566723D00206B -:10547000635F666C73683D002074786D6178733D7E -:10548000002072695F656D733D002020635F6C735F -:10549000723D002020635F6965723D002020635FDC -:1054A0006663723D002020635F6D63723D002020C3 -:1054B000635F6C63723D002020635F6473733D0023 -:1054C00020635F647373693D0020635F647373726C -:1054D0003D002020635F6973723D002020635F639D -:1054E00061723D002020635F6566723D0020635F4E -:1054F000657273743D0020635F65636E743D0020C8 -:10550000635F62726B633D0020635F626F6B633D3C -:105510000020635F7265706C3D0020635F6363739E -:10552000723D0020635F737474313D0020635F73CC -:105530007474323D002BC08ED88EC0E8C200E8E5FE -:1055400000FABF8400C705DC568C4D02BF0C00C7B3 -:10555000056E5E8C4D02BF0400C705BA5E8C4D021D -:10556000E8F10090E84901E81600F490E8E500BE93 -:10557000BA4DE8090CA09312E85D0CE8C209EBE40F -:10558000E8D50CE8C40C0AC074F68B1EF8793C0D03 -:10559000742E3C0874173C7F741383FB207FE188D2 -:1055A00087D67943891EF879E8770CEBD30BDB7447 -:1055B000CF4B891EF8798B36167AE8C10BEBC19078 -:1055C000E80200EBBBC687D679000BDB741EA0D6C1 -:1055D00079BF6051B91D008BD9060E07F2AE077571 -:1055E00017412BD9D1E32EFF977D519033C0A3F8FB -:1055F00079BE894DE8870BC3BE8D4DE8800BEBEC7F -:10560000BA0002B093EEB055EEBA1002B093EEB00D -:10561000AAEEBA0002EC3C557508BA1002EC3CAA9E -:105620007403E82FF6C3BA0402B01AEEB020EEB04D -:1056300030EEB040EEB080EEBA0002B013EEB0072C -:10564000EEBA0802B080EEBA0202B0BBEEBA0402B3 -:10565000B005EEC3C606CA1301C706F8790000C636 -:1056600006F67901C706D0790000C706D279000096 -:10567000C706D4790000C706FA790000C706FC798E -:105680000000C706FE790000C706007A0000C706C2 -:10569000027ACE598C0E047AC706067A0000C70635 -:1056A000277A0000C606297A00C6062A7A00C39027 -:1056B000BE224DE8C80AE83F002C313C0177F7E8EC -:1056C00081098B360C7AE8B50ABE6A4DE8AF0A0E3E -:1056D00058E8F80ABE7A4DE8A40AC39060D1E38383 -:1056E000FB1873111EBA00008EDA2EFF97B7518B8C -:1056F000EC8946101F61CF90E84F0B0AC07505E892 -:10570000560BEBF4C390833EF879017416BED7793B -:10571000E8310A8BD0AC3C2C74043C207505E8239E -:105720000AEEC3E9D2FE833EF8790174F6BED7795A -:10573000E8110A8BD0AC3C2C74083C207404E9B707 -:10574000FE90E8FF09EFC3908B16067A833EF87946 -:1057500001740BBED779E8EB098BD0A3067AB02091 -:10576000E8570B8B16067AECE86F0BC38B16067A9C -:10577000833EF87901740BBED779E8C7098BD0A3B3 -:10578000067AB020E8330B8B16067AEDE8670BC378 -:10579000FAC606F67900C390C606F67901FBC390F7 -:1057A00006E85809B020E8110B268B05E8470BB036 -:1057B00008E8060BE8030BE8000BE8FD0AB8010057 -:1057C000E8CFF4BA0202EC24017502EBDCBA06025F -:1057D000EC07C390C706087A1000EB06C706087AE4 -:1057E0000100068E06FC798B3EFA79E80E09E80B7B -:1057F00000893EFA798C06FC7907C390BEB24DE869 -:105800007C098B16087A52E82A09E80F0AE80C0A84 -:1058100033DBB9100090268A01E8BC09E8FD094392 -:10582000E2F4E8F709E8F40933DBB9100090268ABE -:10583000013C2072053C7E760390B02EE8E30943DC -:10584000E2ECBEB24DE8360983C7105A4A75B7C3B9 -:10585000068E06007A8B3EFE79E8A008893EFE7926 -:105860008C06007A578B360E7AE81209C706087A3A -:105870001000BA0002E8E800E881FF5FBA0000E823 -:10588000DE00BEB54DE8F6088CC0E83F09B03AE846 -:1058900090098BC7E83509E87E08E8C30090E8B7AF -:1058A00009E8A6090AC074F63C0B750683EF10EBF5 -:1058B00019903C0A750683C710EB0F903C0C7504D9 -:1058C00047EB07903C0875244F908B36FE798BC7C9 -:1058D0002BC63D000172A53D1001720483EE20909D -:1058E00083C6108936FE79578BFEEB803C2E7508F7 -:1058F000BA0113E86A0007C3C6060A7A0232C990E1 -:105900003C30724C3C39760C245F3C4172423C4640 -:10591000773E2C072C3050E8CC085802C8FE0E0AFF -:105920007A740FC0E104E82F09E81E090AC074F672 -:10593000EBCE26880DE8E0078AD0E823008AC13C38 -:105940002072053C7E760390B02EE8D508E970FF02 -:10595000E8C507E80A00268A05E87C08E91DFF90EB -:10596000F606267A02750286F2528B361A7AE80D0E -:10597000085A528AC60206247AF606267A01750665 -:10598000E89F08EB0D9032E4E80D088B361C7AE8AE -:10599000EC075A8AC20206257AF606267A017506AF -:1059A000E87F08EB069032E4E8ED078B361E7AE8D4 -:1059B000CC07C390068E06047A8B3E027AE83C0739 -:1059C000893E027A8C06047A07FF1E027AC3BE97CC -:1059D0004DE8AA07CB900657BED779E866078BD863 -:1059E000E861078BC82BCB78118EC3BF0000B8FFCE -:1059F000FF51B90800F3AB59E2F75F07C39006BE49 -:105A0000D779E83F078BD8D1E32E8B9F4400BE2681 -:105A100052E8F1088BC3E8DD08B80100E873F2E84A -:105A2000E008BE2F52E8DD088B4718E8C808BE77AB -:105A300052E8D1088B4726E8BC08BE5352E8C50897 -:105A40008B471EE8B008BE5C52E8B9088B4720E8D7 -:105A5000A408BE6E52E8AD088B4724E89808BE80C3 -:105A600052E8A1088B472AE88C08E89508BE38520E -:105A7000E892088B07E87E08BE4152E887088B470A -:105A80001AE87208BE4A52E87B088B471CE8660891 -:105A9000BE6552E86F088B4722E85A08E86308BEE3 -:105AA000D152E860088B4738E84B08BEAD52E85445 -:105AB000088B4730E83F08BEB652E848088B4732AB -:105AC000E83308BEA452E83C088B472EE82708BEFE -:105AD000BF52E830088B4734E81B08E82408BE8929 -:105AE00052E821088B4704E80C08BE9252E81508DA -:105AF0008B4714E80008BE9B52E809088B472CE846 -:105B0000F407BEC852E8FD078B4736E8E807BEDA5F -:105B100052E8F1078B473AE8DC07BEE352E8E507B5 -:105B20008B473CE8D007E8D907BE1953E8D6078B66 -:105B30004748E8C107BEFE52E8CA078B4742E8B5AE -:105B400007BE0753E8BE078B4744E8A907BE7C534E -:105B5000E8B2078B474CE89D07BE8553E8A6078B44 -:105B6000474EE89107BE8E53E89A078B4750E88569 -:105B700007E88E07BE2253E88B078B474AE8760773 -:105B8000BEEC52E87F078B4708E86A07BEF552E88B -:105B900073078B4740E85E07BE1053E867078B47E3 -:105BA00046E85207E85B07BE6A53E858078B477A16 -:105BB000E84307BE3D53E84C078B4770E83707BE04 -:105BC0004653E840078B4772E82B07BE4F53E83433 -:105BD000078B4774E81F07E82807BE2B53E8250703 -:105BE0008B470CE81007BE3453E819078B4710E8C1 -:105BF0000407BE5853E80D078B4776E8F806BE61E8 -:105C000053E801078B4778E8EC06BE7353E8F506C6 -:105C10008B473EE8E006E8E906BE9753E8E6068BC8 -:105C20004752E8D106BEA053E8DA068B4754E8C5D0 -:105C300006BEA953E8CE068B4756E8B906BEB25356 -:105C4000E8C2068B4758E8AD06BEBB53E8B6068BE4 -:105C5000475AE8A106BEC453E8AA068B475CE895FC -:105C600006E89E06BECD53E89B068B475EE8860697 -:105C7000BED653E88F068B4760E87A06BEDF53E84E -:105C800083068B4762E86E06BEE853E877068B47CB -:105C90007CE86206BEF153E86B068B477EE8560649 -:105CA000BEFA53E85F068B878000E84906E8520693 -:105CB000BE4254E84F068B879E00E83906BE035467 -:105CC000E842068B4764E82D06BE0C54E836068B86 -:105CD000476EE82106BE1554E82A068B878E00E839 -:105CE0001406BE1E54E81D068B879000E80706BE0A -:105CF0002754E810068B879200E8FA05E80306BEF1 -:105D00003054E800068B879400E8EA05BE3954E871 -:105D1000F3058B879600E8DD05BE6F54E8E6058B3A -:105D2000879800E8D005BE5D54E8D9058A87A000B1 -:105D3000E8A705BE5454E8CC058A4728E89B05BE71 -:105D40006654E8C0058A87A100E88E05E8B305BE61 -:105D50007854E8B0058A87A200E87E05BE8154E841 -:105D6000A3058A87A300E87105BE8A54E896058AD0 -:105D700087A400E86405BE9354E889058A87A500D6 -:105D8000E85705BE9C54E87C058A87A600E84A05CA -:105D9000BEA554E86F058A87A700E83D05BEAE544E -:105DA000E862058A87A800E83005E85505BEB754C3 -:105DB000E852058A87A900E82005BEC054E84505D9 -:105DC0008A87AA00E81305BEC954E838058A87AB5C -:105DD00000E80605BED254E82B058A87AD00E8F935 -:105DE00004BEDB54E81E058A87AE00E8EC04BEE47E -:105DF00054E811058A87AF00E8DF04BEED54E804DB -:105E0000058A87B000E8D204E8F704BEF654E8F447 -:105E1000048A87B100E8C204BEFF54E8E7048A8719 -:105E2000B200E8B504BE0855E8DA048A87B300E892 -:105E3000A804BE1155E8CD048A87BB00E89B04E89E -:105E4000C004BE1A55E8BD048A87BC00E88B04BEB6 -:105E50002355E8B0048A87BE00E87E04BE2C55E8CE -:105E6000A3048A87BF00E87104E8960407C36006AC -:105E70001E168BECFF4E16F7461A00027401FBB893 -:105E800000008ED88EC0892E2D7AE8CB0081661A4C -:105E9000FFFEC6062A7A00E8D800B8005FA32B7A76 -:105EA000E85D00803E2A7A00740A814E1A0001C61D -:105EB000062A7A00171F0761CF9060061E168BEC2A -:105EC000F7461A00027401FBB800008ED88EC08914 -:105ED0002E2D7A81661AFFFEC6062A7A00E8920005 -:105EE000B8005FA32B7AE81700803E2A7A00740A74 -:105EF000814E1A0001C6062A7A00171F0761CF904B -:105F0000B8F000E88CEDFF262B7AC390065356803C -:105F10003E297A007403E83F00BED779E825028B5A -:105F2000D8A3277A2E8A07A2297AB0CC2E88075EBA -:105F30005B07C3C6062A7A00B80A5FA32B7AC39010 -:105F40008B2E2D7AE82B00C3C6062A7A01E80800BA -:105F5000B80A5FA32B7AC39057803E297A00740F4A -:105F60008B3E277AA0297A2E8805C606297A005FFB -:105F7000C390BEB24DE80602BED851E80002FF76DB -:105F80001458E84702BEDE51E8F301FF760E58E8E8 -:105F90003A02BEE451E8E601FF761258E82D02BE4F -:105FA000EA51E8D901FF761058E82002BE1452E801 -:105FB000CC01FF760A58E81302BE1A52E8BF01FF6F -:105FC000760C58E80602BECF51E8B201FF761A58A7 -:105FD000E8F901BEB24DE8A501BEF051E89F01FF0E -:105FE000761858E8E601BEF651E89201FF760258AD -:105FF000E8D901BEFC51E88501FF760458E8CC01E0 -:10600000BE0252E87801FF760058E8BF01BE085290 -:10601000E86B01FF760658E8B201BE0E52E85E0159 -:10602000FF760858E8A501BE2052E85101FF761618 -:1060300058E89801BE894DE84401C390BEC94DE8B7 -:106040003C01C33C0074053C017459C3C7060C7A7B -:10605000CD50C7060E7AF050C706107AE850C70632 -:10606000127AEC50C706147AF450C706167AFB5021 -:10607000C706187A0351C7061A7A0B51C7061C7A4D -:106080000E51C7061E7A1051C706207A1251C70654 -:10609000227A1651C606247A01C606257A01C6065A -:1060A000267A03C3C7060C7A1A51C7060E7A4D51D9 -:1060B000C706107A4751C706127A4A51C706147AA2 -:1060C0004F51C706167A5151C706187A5551C7065F -:1060D0001A7A5651C7061C7A5951C7061E7A5A5168 -:1060E000C706207A5B51C706227A5E51C606247A1B -:1060F00020C606257A20C606267A02C3A1F879486A -:106100007414BED779E83C008BF8AC3C3A75078E26 -:10611000C7E830008BF8C3908BC72B06FE798AF056 -:10612000240F8AD002D002D080C20BC0EE0480C6F9 -:1061300003043DC38CC0E89300B03AE8E4008BC789 -:10614000E88900C35133C990AC3C2074FB900AC06D -:1061500074262C3072223C0976143C11721A2C07DA -:106160003C0F760A3C2A72102C203C0F770A98C10B -:10617000E10403C8ACEBD7904E8BC159C390068C99 -:10618000C88EC0E8020007C3268A04460AC0740607 -:10619000E88F00EBF390C3900BC0747A5133D2B9FF -:1061A000E803F7F18BCAE803008BC159BA6400F623 -:1061B000F2E80C008AC498B20AF6F2E802008AC437 -:1061C000500AF074050430E8580058C386C4E80744 -:1061D0000086C4E80200C390C1C804E80800C1C03A -:1061E00004E80200C3905350240FBBCA622ED7E8C4 -:1061F0003000585BC39086C4E8070086C4E80200FC -:10620000C39050B908008AE032C0D1C00430E81110 -:1062100000E2F558C390B030E80700C3B020E801B1 -:1062200000C3568B36D0798884D0774681E6FF014B -:10623000FF06D4798936D079813ED479FE0175087C -:1062400056E814005EEBF1905EC3BA0202EC240142 -:106250007404BA0602ECC390803EF67900740960BB -:10626000B80100E82CEA6190BA0202ECA804742894 -:106270008B36D279833ED47900741D8A84D07746D8 -:1062800081E6FF018936D279FF0ED479BA0602EE93 -:10629000BA0202ECA80475DCA1D479C352BA060292 -:1062A000EE5AC3905250BA0202ECA8047408585A2D -:1062B000E8E9FFF9C390585AF8C35250BA0202EC09 -:1062C000A80474FB585AE8D3FFC330313233343555 -:1062D0003637383941424344454653508AE080E4DA -:1062E0000FBBCA62C0E8042ED7E8CEFF8AC42ED7FF -:1062F000E8C7FF585BC386E0E8DFFF86E0E8DAFF27 -:10630000C390BEB24D502EAC3C007405E8ABFFEB21 -:10631000F558C390C808000056578B7604BF040098 -:10632000C746FC0000C746FA0000C746F8000083D5 -:106330007E0600750E56E8B60E590BC075058BC764 -:10634000E95B018B46FC8946FE0BFF7505B8010031 -:10635000EB0233C05056E8A40D5959B4008946FCED -:106360008B5EFC83FB087603E92B01D1E32EFFA7AC -:10637000B264B80300E92601837EFA007414C746AC -:10638000FA00008A445898508A44599850E8C20F3D -:106390005959837EF800740AC746F8000056E89BF6 -:1063A0000859837E060075058BC7E9F10083FF0459 -:1063B0007503E9E6008BC7E9E400837EFE00750300 -:1063C000BF0200E9D500837EFE007503BF0100E92E -:1063D000C9008B5EFE83FB077603E98600D1E32EBE -:1063E000FFA7A26433FFE97F00BF0400807C580F41 -:1063F0007422837EF800751CFE44586A0856E87EB5 -:106400000C59598A445804805056E8720C5959C79F -:1064100046FA0100837EF800740AC746F800005669 -:10642000E8190859EB42BF0400807C5800742283AD -:106430007EF800751CFE4C586A0856E8410C595904 -:106440008A445804805056E8350C5959C746FA0119 -:1064500000837EF800740AC746F8000056E8DC079F -:1064600059EB05BF0400EB00EB31BF0400EB2CC778 -:1064700046F801006A0856E8050C5959807C58090D -:106480007D04B00FEB02B00004805056E8F00B59C9 -:1064900059BF0400EB05BF0400EB00E9A5FE5F5EF9 -:1064A000C9C3E4636364636463646364E963266427 -:1064B00051647863BA63C6639664D2636A646A643B -:1064C0006F647263C808000056578B76048B7E0891 -:1064D0006A0156E8A90B59598A4606C0E0060480AD -:1064E0005056E89A0B5959C746FE0000897EF8EBD2 -:1064F00003FF46FE8B5EF8FF46F8803F0075F2838F -:106500007EFE107D25B810002B46FED1F88946FC92 -:10651000C746FA0000EB0B6A2056E8620B5959FF98 -:1065200046FA8B46FA3B46FC7CEDEB0C8BDF478A48 -:10653000075056E8490B5959803D0075EF6A0256DD -:10654000E83C0B5959EB005F5EC9C3C80400005614 -:10655000578B7E04C746FE0000BE1400E909018B7C -:106560005EFE83C3042BDF8A87AC0B88445AC64483 -:1065700058088A46FE884459C744060000C6441994 -:1065800000C6441A00C6441B00C6441D0DC6441E66 -:1065900003C6441F00C6442000C6442100C6445B15 -:1065A00000C6445D00C6445E00C6445F00C6446049 -:1065B00000C746FC0000EB0D8B5EFCD1E3C740300A -:1065C0000000FF46FC837EFC107CEDC746FC00000B -:1065D000EB0A8B5EFCC6405000FF46FC837EFC0449 -:1065E0007CF0C744540000C7445600008A445A98BF -:1065F000BAF80023D0B805000BC28946FC9CFA8A81 -:1066000046FCBAFE00EEBA0000EC9D24088846FC69 -:10661000837EFC007502EB4AFF76FEE87A0C59682F -:10662000350256E8320A59590BC07534683802569B -:10663000E8250A59590BC0752768420256E8180A1E -:1066400059590BC0751A684C0256E80B0A59590B78 -:10665000C0750D68560256E8FE0959590BC0740200 -:10666000EB00FF46FE83C662397EFE7D03E9EFFE46 -:10667000EB005F5EC9C3C808000056578B4604BADA -:106680006200F7EA0514008BF0837E06007405B8FB -:106690001000EB03B808008944048A460888445C6B -:1066A00056E85904598BF88BC78944568944548A53 -:1066B000445D88442F0BFF751D68C20F6A0156E8C0 -:1066C00002FE83C406EB006A0156E847FC59590BE9 -:1066D000C075F4BF0100897EFAB90500BBE96A2ED6 -:1066E0008B073B46FA74074343E2F4E9A4032EFF09 -:1066F000670AC744060200C74408F4088B5E04D149 -:10670000E38B87FC0889440A33C08BF8894454E939 -:10671000800356E8BB0559BF01008A445D88446088 -:10672000E96F03837C04087530807C5C0175158AF1 -:10673000445DB400D1E08BD8FFB7E40856E8F70811 -:106740005959EB138A445DB400D1E08BD8FFB7C42C -:106750000856E8E2085959EB2E807C5C0175158AD1 -:10676000445DB400D1E08BD8FFB7D40856E8C70821 -:106770005959EB138A445DB400D1E08BD8FFB7B40C -:106780000856E8B20859596A0156E887FB59598BEF -:10679000D883FB03772AD1E32EFFA7E16ABF01006C -:1067A0008A445D88445EEB188A445D04FF240788B0 -:1067B000445DEB0C8A445DFEC0240788445DEB0019 -:1067C000E9CF028A445DB400D1E08BD8FFB7FD0267 -:1067D00056E863085959681D0356E85A0859596A1A -:1067E0000156E82FFB59598BD883FB037736D1E349 -:1067F0002EFFA7D96ABF01008A445D88445FEB245D -:106800008A445D04FF8A540480C2FF22C288445D2A -:10681000EB128A445DFEC08A540480C2FF22C28803 -:10682000445DEB00E96B028B5C0683C3FED1E38B16 -:10683000400889048B1CFF77066A0056E885FC83B4 -:10684000C4068B5C064BD1E38B40088944028B5C09 -:1068500002FF77066A0156E86AFC83C4066A01569D -:10686000E8B1FA59598BD883FB037603E91F02D1AB -:10687000E32EFFA7D16A8B5C028B47048944028B0D -:106880005C02803F44750D8B5C028A4701B4003B7B -:1068900044047DE28B4604D1E08B1C03D88B440278 -:1068A0008947088B5C064BD1E38B4402894008E999 -:1068B000DE018B5C028B47028944028B5C02803FC5 -:1068C00044750D8B5C028A4701B4003B44047DE2B1 -:1068D0008B4604D1E08B1C03D88B44028947088B7C -:1068E0005C064BD1E38B4402894008E9A201BF0159 -:1068F00000E99C018B5C028A07B4008946F8B90C58 -:1069000000BBA16A2E8B073B46F874074343E2F4B1 -:10691000E977012EFF67188B4604D1E08B5C0203F8 -:10692000D88B47088B5C06FF4406D1E38940088B6F -:106930001C807F010074128B5C028A47018B1C8AC9 -:106940005701B6008BDA884018E94001FF4C06E990 -:106950003A018B5C028A47018B1C8A5701B6008B77 -:10696000DA884018E925018B5C028A47018B1C8A72 -:106970005701B6008BDA884018FF4C06E90D018BF1 -:106980005C028A47018B1C8A5701B6008BDA3040C3 -:1069900018E9F800B8F0108BF88944548A445F88ED -:1069A000445DE9E7008A441C983D020074073D03FA -:1069B000007402EB07C746FE0000EB2B8A441C98CC -:1069C000D1E08BD8FFB7690256E86B0659596A01C6 -:1069D00056E840F959598946FE837EFE00740683C5 -:1069E0007EFE0375E9EB00837EFE0374628A441C1D -:1069F00098D1E08BD8FFB76D0256E83A0659595640 -:106A0000E84D97598946FC8B5EFC83EBFE83FB03C4 -:106A10007733D1E32EFFA7996A68AC0256E81706D0 -:106A20005959EB23688F0256E80C065959EB186840 -:106A3000750256E801065959EB0D68C60256E8F68C -:106A4000055959EB02EB006A0156E8C7F85959BFDE -:106A50000100EB3868DD0256E8DC0559596A015639 -:106A6000E8B1F85959BF0100EB22B8D0308BF88952 -:106A700044548A446088445DEB12B8E0208BF88966 -:106A800044548A445E88445DEB02EB00EB02EB0069 -:106A9000EB00E941FC5F5EC9C3196A246A2F6A3AB8 -:106AA0006A0000010002000400410042004300446B -:106AB00000800081008200FF001769546A7A6AA58D -:106AC00069526994696A6A676952697F6967694C42 -:106AD00069F4687668B268EE68F56700681268F570 -:106AE000679D67A867B4679D6700000100F010E02C -:106AF00020D0302768F266C36723671267C8040096 -:106B00000056578B76048A4459988946FC6A098B4B -:106B100046FC05840150E8930859598BF88BC7252A -:106B200000F03D001075558BC725F0003DF0007555 -:106B30004B8BC725000FC1F8088946FE8B44043BE8 -:106B400046FE7D0533C0E9EF008BC7250F00BA0F65 -:106B5000002BD03B56FE740533C0E9DB00C744026E -:106B600004098A46FE88445F88445D8B5EFCD1E35D -:106B7000C787FC080409B8F010E9BC008BC72500E2 -:106B8000F03D002075528BC725F0003DE0007548B0 -:106B90008BC725000FC1F8088946FE837EFE087E5C -:106BA0000533C0E992008BC7250F00BA0F002BD028 -:106BB0003B56FE740533C0EB7F90C744020C098A34 -:106BC00046FE88445E88445D8B5EFCD1E3C787FC4B -:106BD000080C09B8E020EB608BC72500F03D0030C1 -:106BE00075528BC725F0003DD00075488BC7250036 -:106BF0000FC1F8088946FE8B44043B46FE7D0433F2 -:106C0000C0EB358BC7250F00BA0F002BD03B56FECB -:106C1000740433C0EB22C7440214098A46FE884438 -:106C20006088445D8B5EFCD1E3C787FC081409B81B -:106C3000D030EB0433C0EB005F5EC9C3C806000070 -:106C4000568B76046A0856E8350459598A44580424 -:106C5000805056E8290459598B44543B4456750AD0 -:106C60008A445D3A442F7502EB648B445489445640 -:106C70008B5C028A470188442F8A445DB400C1E0DE -:106C8000088B54540BD08A445DB400BB0F002BD842 -:106C90000BD38956FE6A108A445998050400990559 -:106CA000400183D2005250E8540883C4068956FC40 -:106CB0008946FA8B46FE0946FA834EFC006A19FFA4 -:106CC00076FCFF76FAE8730783C406E8FE075EC920 -:106CD000C3C81C000056578B5E048A4759988BF036 -:106CE0008B5E048A475DB4008946E6837EE6007DBC -:106CF0000A8B5E048B4704488946E68B5E048B470B -:106D0000043B46E67F05C746E600008B5E048A46E4 -:106D1000E688475D8BDED1E38B9F5902C647022090 -:106D20008BDED1E38B9F5902C64703308BDED1E364 -:106D30008B9F6102C64702208BDED1E38B9F6102ED -:106D4000C64703308B46E68946FA837EFA007418FC -:106D50008B46FABB0A0033D2F7F380C2308BDED108 -:106D6000E38B9F5902885703BB0A008B46FA33D244 -:106D7000F7F38946FA837EFA0074188B46FABB0A49 -:106D80000033D2F7F380C2308BDED1E38B9F590200 -:106D90008857028B46E68946FA837EFA0074188B80 -:106DA00046FABB0A0033D2F7F380C2308BDED1E360 -:106DB0008B9F6102885703BB0A008B46FA33D2F7D8 -:106DC000F38946FA837EFA0074188B46FABB0A00F0 -:106DD00033D2F7F380C2308BDED1E38B9F61028820 -:106DE00057028B5EE6D1E3FFB712026A00FF76041A -:106DF000E8D1F683C40668D30F6A01FF7604E8C3BE -:106E0000F683C406FF76E656E8019359598956F28F -:106E10008946F0FF76E656E8149359598956EE896B -:106E200046EC9CFAC45EF0268B078946EAC45EEC09 -:106E3000268B078946E8BA50FFED8946FE9DC74676 -:106E4000E40100E8EEA0BA50FFED8946FC8B46FC59 -:106E50002B46FE3DE8037303E980019CFABA50FF1C -:106E6000ED8946FC8B46FC2B46FE8946F8C45EF055 -:106E7000268B072B46EA8946F6C45EF0268B0789E7 -:106E800046EAC45EEC268B072B46E88946F4C45ECE -:106E9000EC268B078946E8BA50FFED8946FE9D81B6 -:106EA0007EF8E803761CFF76F8FF76F6E87601595F -:106EB000598946F6FF76F8FF76F4E8680159598952 -:106EC00046F4BF0E00EB178BDED1E38B9F5902C651 -:106ED00001208BDED1E38B9F6102C601204783FF37 -:106EE0001176E48BDED1E38B9F5902C6470D308BC0 -:106EF000DED1E38B9F6102C6470D30837EF60977B2 -:106F000005B80D00EB26837EF6637705B80E00EB1F -:106F10001B817EF6E7037705B80F00EB0F817EF645 -:106F20000F277705B81000EB03B811008BF8EB259D -:106F30008B46F6BB0A0033D2F7F380C2308BDED12A -:106F4000E38B9F590288114FBB0A008B46F633D260 -:106F5000F7F38946F6837EF60075D5837EF40977CC -:106F600005B80D00EB26837EF4637705B80E00EBC1 -:106F70001B817EF4E7037705B80F00EB0F817EF4E9 -:106F80000F277705B81000EB03B811008BF8EB253D -:106F90008B46F4BB0A0033D2F7F380C2308BDED1CC -:106FA000E38B9F610288114FBB0A008B46F433D2FA -:106FB000F7F38946F4837EF40075D58BDED1E3FFC9 -:106FC000B75902FF7604E86E0059598BDED1E3FF12 -:106FD000B76102FF7604E85E0059596A00FF760443 -:106FE000E831F359598BD883FB04771FD1E32EFF87 -:106FF000A71B70EB22C746E40000FF4EE6EB0CC770 -:1070000046E40000FF46E6EB02EB00837EE40074FA -:1070100003E92AFEE9D4FC5F5EC9C3F36FF56FFF95 -:107020006FF36F0970558BEC8B4604B9E803F7E1F9 -:107030008B4E06F7F15DC3558BEC568B7606EB0E47 -:107040008BDE468A0750FF7604E833005959803CAE -:107050000075EDEB005E5DC3558BEC568B7606EB51 -:10706000148BDE468A0750FF7604E8450059590B19 -:10707000C07402EB07803C0075E7EB005E5DC3C89F -:10708000020000568B76048A445A988946FE9CFA80 -:107090008A46FEBAFE00EEBA0200ECA80274069D13 -:1070A000E8919EEBE9BA00008A4606EE9DEB005E91 -:1070B000C9C3C8040000568B76048A445A9889468E -:1070C000FEE8E6A18946FCE8E0A12B46FC3DB80BB2 -:1070D0007605B80100EB239CFA8A46FEBAFE00EE64 -:1070E000BA0200ECA80274069DE8489EEBD9BA00EB -:1070F000008A4606EE9D33C0EB005EC9C3C804009B -:107100000056578B7604837E0600740756E8030109 -:1071100059EB0556E8A200598846FF807EFF0877A4 -:10712000068A46FFE98400807EFF0F7603EB7990A4 -:107130008A46FFB4002D0A008BD883FB047767D101 -:10714000E32EFFA7AF71B000EB6156E86B0059B4B6 -:1071500000250F008946FC56E85E0059B4008BF804 -:1071600056E8550059B400C1E0088BD703D08BFA1C -:107170008B5EFCD1E3897830EB2E56E83B005988D2 -:10718000445BEB2456E831005988445056E8290006 -:107190005988445156E821005988445256E819004C -:1071A00059884453EB02EB00E95BFF5F5EC9C346BD -:1071B00071A6714A717A718471C8040000568B7689 -:1071C000048A445A988946FE9CFA8A46FEBAFE0012 -:1071D000EEBA0200ECA80175069DE8579DEBE9BAEE -:1071E0000000EC8846FD9D8A46FDEB005EC9C3C8E1 -:1071F000020000568B76048A445A988946FE9CFA0F -:107200008A46FEBAFE00EEBA0200EC32E424019D8A -:107210005EC9C3C8060000568B76048A445A988912 -:1072200046FEE885A08946FAE87FA02B46FA3DB8DD -:107230000B7604B008EB249CFA8A46FEBAFE00EEF8 -:10724000BA0200ECA80175069DE8E89CEBDABA00EA -:1072500000EC8846FD9D8A46FDEB005EC9C3558B58 -:10726000EC568B56048A4606EE33F6EB035058462E -:1072700083FE147CF85E5DC3C8020000568B560482 -:10728000EC8846FF33F6EB0350584683FE147CF837 -:107290008A46FFEB005EC9C3C802000056578B76D2 -:1072A00004833EB00B00751FBA8801B000EEBA86A9 -:1072B00001B000EE6A096A00683001E87D0183C40C -:1072C00006C706B00B01006A098BC605800150E8AD -:1072D000DA0059598BF88BC7C1E80C250F00894695 -:1072E000FE8BC7C1E808250F008B56FE83F20C3BCE -:1072F000C275218BC7C1E804250F008B56FE83F2AF -:10730000063BC2750F8BC7250F008B56FE83F20913 -:107310003BC2740D6A0756E838005959C746FE0744 -:10732000008A46FE0480A233028BC6BA6200F7EAE6 -:107330008A56FE8BD888976C006832028BC6BA6278 -:1073400000F7EA05140050E80EFD5959EB005F5EA6 -:10735000C9C3C8020000568B760683E60F8BC6C1F0 -:10736000E00C8BD683F20CC1E2080BC28BD683F201 -:1073700006C1E2040BC28BD683F2090BC28946FE1A -:107380006A196A108B46049905400183D200525055 -:10739000E86B0183C4060B46FE83CA005250E89A8C -:1073A0000083C406E82501EB005EC9C3558BEC568B -:1073B0005733FF6A01688601E8A3FE5959B1102AC4 -:1073C0004E06D3660433F6EB2E817E0400807204F1 -:1073D000B001EB02B00050688801E881FE59596A9B -:1073E00003688601E877FE59596A01688601E86DED -:1073F000FE5959D16604463B76067CCD33F6EB2424 -:10740000D1E76A03688601E854FE59596A01688623 -:1074100001E84AFE5959688801E85CFE599825013F -:10742000000BF84683FE107CD76A00688601E82DC1 -:10743000FE59598BC7EB005F5E5DC3558BEC565709 -:107440008B7E086A01688601E813FE5959B820004E -:107450002BC750FF7606FF7604E8A20083C4068996 -:10746000560689460433F6EB47817E060080720C8F -:107470007506837E04007204B001EB02B000506810 -:107480008801E8D9FD59596A03688601E8CFFD599A -:10749000596A01688601E8C5FD59596A01FF7606F7 -:1074A000FF7604E8580083C40689560689460446D8 -:1074B0003BF77CB56A00688601E8A2FD59596A006D -:1074C000688601E898FD59595F5E5DC3558BEC569F -:1074D0006A01688601E886FD595933F6EB00688831 -:1074E00001E894FD59A80175088BC6463D64007CEF -:1074F000ED6A00688601E865FD59595E5DC3C80400 -:1075000000008B46048B56068B4E08E306D1E0D173 -:10751000D2E2FA8946FC8956FE8B56FE8B46FCEB7E -:1075200000C9C300000000000000000000000000CF -:1075300050726576696F7573204D656E7500426592 -:1075400067696E00000000000000000000000000FD -:10755000000000000000000000000000000000002B -:10756000000000000000000000000000000000001B -:10757000000000000000000000000000000000000B -:1075800000000000000000000000000000000000FB -:1075900000000000000000000000000000000000EB -:1075A00000000000000000000000000000000000DB -:1075B00000000000000000000000000000000000CB -:1075C00000000000000000000000000000000000BB -:1075D00000000000000000000000000000000000AB -:1075E000000000000000000000000000000000009B -:1075F000000000000000000000000000000000008B -:10760000000000000000000000000000000000007A -:10761000000000000000000000000000000000006A -:10762000000000000000000000000000000000005A -:10763000000000000000000000000000000000004A -:10764000000000000000000000000000000000003A -:10765000000000000000000000000000000000002A -:10766000000000000000000000000000000000001A -:10767000000000000000000000000000000000000A -:1076800000000000000000000000000000000000FA -:1076900000000000000000000000000000000000EA -:1076A00000000000000000000000000000000000DA -:1076B00000000000000000000000000000000000CA -:1076C000000000000000000000000000506F727415 -:1076D000203000506F7274203100506F727420326D -:1076E00000506F7274203300506F72742034005059 -:1076F0006F7274203500506F7274203600506F72B4 -:1077000074203700506F7274203800506F727420EC -:107710003900506F727420313000506F7274203114 -:107720003100506F727420313200506F727420310A -:107730003300506F727420313400506F72742031F6 -:1077400035009C01A301AA01B101B801BF01C60126 -:10775000CD01D401DB01E201EA01F201FA010202EA -:107760000A02080000078100038080809F919591A4 -:107770009F000381848E95848484840003828484A2 -:107780008484958E8400048800B20BC60BDA0BEE5D -:107790000B020C160C2A0C3E0C520C770C9C0CBEE7 -:1077A0000CE00C020D01802054657374205061734D -:1077B000736564201F20507265737320800200017E -:1077C00080204D697373696E67205278204461741C -:1077D000611F205072657373208002000180204277 -:1077E00061642052782044617461201F20507265CA -:1077F000737320800200018020586D7472204275DE -:1078000073791F20507265737320800200018020FD -:107810006E6F742063757272656E746C791F2020B0 -:10782000696D706C656D656E7465640200240D2F62 -:107830000D3A0D450D500D5B0D660D710D7C0D87DC -:107840000D920D9D0DA80DB30DBE0DC90D53802CCD -:107850003254442053862C334454522053822C33C8 -:10786000525453201F53812C3252442053852C32C2 -:1078700043442053832C334354532053842C3344A8 -:1078800053522053872C3252492702000180202076 -:10789000444344202D2070696E2032301F275385C9 -:1078A0002E31818263908081828384858687888956 -:1078B0008A8B8C8D8E8F27020001802020445352AA -:1078C000202D2070696E2031311F2753842E318185 -:1078D000826390808182838485868788898A8B8C65 -:1078E0008D8E8F27020001802020435453202D20AD -:1078F00070696E20341F2753832E318182639080FC -:107900008182838485868788898A8B8C8D8E8F2758 -:107910000200018020205249202D2070696E203203 -:10792000321F2753872E3181826390808182838426 -:1079300085868788898A8B8C8D8E8F2702000180AF -:107940002020445452202D2070696E20362F381F7D -:107950002753862E3181826390808182838485863D -:107960008788898A8B8C8D8E8F270200018020204A -:10797000525453202D2070696E20351F2753822EBC -:107980003181826390808182838485868788898A19 -:107990008B8C8D8E8F27020001802020527844200E -:1079A0002D2070696E20321F2753812E30534D8158 -:1079B000826390808182838485868788898A8B8C84 -:1079C0008D8E8F27020001802020547844202D20A6 -:1079D00070696E20331F2753802E30534D81826390 -:1079E00090808182838485868788898A8B8C8D8E1E -:1079F0008F27020001802020444344202D207069FD -:107A00006E20351F2753852E3181826390808182BD -:107A1000838485868788898A8B8C8D8E8F27020048 -:107A200001802020445352202D2070696E20351F84 -:107A30002753842E3181826390808182838485865E -:107A40008788898A8B8C8D8E8F2702000180202069 -:107A5000435453202D2070696E20311F2753832EED -:107A60003181826390808182838485868788898A38 -:107A70008B8C8D8E8F270200018020205249202D73 -:107A800020286E2E632E291F2753872E3181826373 -:107A900090808182838485868788898A8B8C8D8E6D -:107AA0008F27020001802020445452202D2070692D -:107AB0006E20321F2753862E31818263908081820F -:107AC000838485868788898A8B8C8D8E8F27020098 -:107AD00001802020525453202D2070696E20371FC2 -:107AE0002753822E318182639080818283848586B0 -:107AF0008788898A8B8C8D8E8F27020001802020B9 -:107B0000527844202D2070696E20361F2753812E15 -:107B100030534D81826390808182838485868788FB -:107B2000898A8B8C8D8E8F270200018020205478CB -:107B300044202D2070696E20331F2753802E305330 -:107B40004D81826390808182838485868788898A3B -:107B50008B8C8D8E8F27020001802020444344208F -:107B60002D2070696E20351F202020202753852E60 -:107B700031818263888081828384858687270200A1 -:107B800001802020445352202D2070696E20351F23 -:107B9000202020202753842E318182638880818297 -:107BA0008384858687270200018020204354532048 -:107BB0002D2070696E20311F202020202753832E16 -:107BC0003181826388808182838485868727020051 -:107BD000018020205249202D20286E2E632E291F3F -:107BE000202020202753872E318182638880818244 -:107BF00083848586872702000180202044545220F8 -:107C00002D2070696E20321F202020202753862EC1 -:107C10003181826388808182838485868727020000 -:107C200001802020525453202D2070696E20371F70 -:107C3000202020202753822E3181826388808182F8 -:107C40008384858687270200018020205278442083 -:107C50002D2070696E20361F202020202753812E72 -:107C600030534D8182638880818283848586872713 -:107C7000020001802020547844202D2070696E205D -:107C8000331F202020202753802E30534D818263C4 -:107C90008880818283848586872702000180202056 -:107CA000444344202D2070696E2032301F20202054 -:107CB000202753852E318182638880818283848549 -:107CC000868727020001802020445352202D2070F7 -:107CD000696E2031311F202020202753842E3181CE -:107CE0008263888081828384858687270200018061 -:107CF0002020435453202D2070696E20341F2020F3 -:107D000020202753832E318182638880818283845F -:107D1000858687270200018020205249202D20706F -:107D2000696E2032321F202020202753872E318178 -:107D30008263888081828384858687270200018010 -:107D40002020445452202D2070696E20362F381F79 -:107D5000202020202753862E3181826388808182D3 -:107D60008384858687270200018020205254532077 -:107D70002D2070696E20351F202020202753822E51 -:107D8000318182638880818283848586872702008F -:107D900001802020527844202D2070696E20321FEF -:107DA000202020202753812E30534D8182638880EC -:107DB0008182838485868727020001802020547871 -:107DC00044202D2070696E20331F2020202027534F -:107DD000802E30534D8182638880818283848586A2 -:107DE0008727020068049604B6033C040E04890346 -:107DF0005C03E20360088A08BE0738080E0895078E -:107E00006C07E6071C057405FA05C404F004CC05EC -:107E1000A00548057806C806420728065006180738 -:107E2000F006A0060000F408F408D40D04090409C3 -:107E30000409040942000C091C09E50D020014099B -:107E40000409F40D43001C090C09050E0004040983 -:107E50001409120E2C092C092C092C0900003C09CC -:107E60006C091E0E740974097409740900014C0927 -:107E70002C092D0E740974097409740900025C0937 -:107E80003C093D0E740974097409740900036C09F6 -:107E90004C094D0E7409740974097409FF002C090A -:107EA0005C09000000058409EC095E0EF409F40980 -:107EB000F409F409000694097409680EAC0AAC0AC6 -:107EC000AC0AAC0A0007A4098409720EBC0ABC0AF9 -:107ED000BC0ABC0A0008B40994097C0ED40AD40A6E -:107EE000D40AD40A000BC409A409830EFC0AFC0AB4 -:107EF000FC0AFC0A000CD409B409900E140B140BF4 -:107F0000140B140B0002E409C409A00E2C0B2C0B5B -:107F10002C0B2C0B0400EC09D4090E00FF00740993 -:107F2000E40900008201FC09A40AAC0E8202040AE2 -:107F3000F409AF0E82030C0AFC09B20E8204140A83 -:107F4000040AB60E82051C0A0C0ABC0E8206240A1C -:107F5000140AC00E82072C0A1C0AC40E8208340AB6 -:107F6000240AC80E82093C0A2C0ACC0E820A440A52 -:107F7000340AD10E82104C0A3C0AD60E820B540AE7 -:107F8000440ADB0E82115C0A4C0AE00E820C640A81 -:107F9000540AE50E82126C0A5C0AEA0E820D740A1B -:107FA000640AEF0E820E7C0A6C0AF40E820F840AB9 -:107FB000740AFB0E82138C0A7C0A020F8214940A44 -:107FC000840A090F82159C0A8C0A100F8216A40AD3 -:107FD000940A170F8217F4099C0A1E0F8202B40A32 -:107FE000B40A260F8203AC0AAC0A2D0F8200C40A21 -:107FF000CC0A340F8201CC0ABC0A3F0F8202BC0AB1 -:10800000C40A4D0F8200DC0AF40A590F8201E40A07 -:10801000D40A630F8202EC0ADC0A6E0F8203F40AB0 -:10802000E40A7A0F8204D40AEC0A870F8200040B58 -:108030000C0B930F82010C0BFC0A9B0F8202FC0AB3 -:10804000040BA70F82001C0B240BB00F8201240B22 -:10805000140BB50F8202140B1C0BBE0F4400340B23 -:10806000A40B9C0144013C0B2C0BA3014402440BC8 -:10807000340BAA0144034C0B3C0BB1014404540BD8 -:10808000440BB80144055C0B4C0BBF014406640B68 -:10809000540BC60144076C0B5C0BCD014408740BF8 -:1080A000640BD40144097C0B6C0BDB01440A840B88 -:1080B000740BE201440B8C0B7C0BEA01440C940B17 -:1080C000840BF201440D9C0B8C0BFA01440EA40BA3 -:1080D000940B0202440F2C0B9C0B0A02171F0F2F4C -:1080E0000000018078783A20747820637073202A29 -:1080F0002A2A2A2A0200018078783A20747820639C -:108100007073202A2A2A2A2A0200018078783A20CD -:10811000747820637073202A2A2A2A2A0200018098 -:1081200078783A20747820637073202A2A2A2A2AC1 -:10813000020001C078783A20726320637073202AAD -:108140002A2A2A2A020001C078783A207263206322 -:108150007073202A2A2A2A2A020001C078783A203D -:10816000726320637073202A2A2A2A2A020001C01F -:1081700078783A20726320637073202A2A2A2A2A88 -:1081800002000180496E7374616C6C204C6F6F70DB -:108190006261636B1F5072657373208020746F205F -:1081A000737461727402000180204361626C652007 -:1081B000746F2052656D6F74651F50726573732004 -:1081C0008020746F20737461727402000180204CEF -:1081D0006F63616C204C6F6F706261636B201F2056 -:1081E0002052756E6E696E67202E2E2E0200018061 -:1081F00052656D6F7465204C6F6F706261636B20A8 -:108200001F202052756E6E696E67202E2E2E020082 -:10821000018020496E74726E6C204C6F6F706261C9 -:10822000636B1F202052756E6E696E67202E2E2E96 -:10823000020001805472616E736D69742050617424 -:108240007465726E1F202052756E6E696E67202EE7 -:108250002E2E020001802020303A2027438000018A -:10826000802020313A202743810001802020323AAB -:10827000202743820001802020333A2027438300B7 -:1082800001802020343A20274384000180202035BB -:108290003A202743850001802020363A2027438654 -:1082A0000001802020373A202743870001802020CA -:1082B000383A202743880001802020393A2027437C -:1082C000890001802031303A2027438A0001802034 -:1082D00031313A2027438B0001802031323A202768 -:1082E000438C0001802031333A2027438D000180E8 -:1082F0002031343A2027438E0001802031353A2046 -:1083000027438F002A2A204D61696E20204D656E1B -:1083100075202A2A004D6F6E69746F72206120509B -:108320006F7274004D6F6E69746F722061205369B3 -:10833000676E616C00457374696D617465204350AC -:108340005300446961676E6F7374696373004C6FA7 -:1083500063616C204C6F6F706261636B0052656D7E -:108360006F7465204C6F6F706261636B00496E744F -:10837000726E6C204C6F6F706261636B005472613F -:108380006E736D6974205061747465726E00426121 -:10839000756420526174650044617461204269749F -:1083A000730053746F702042697473005061726976 -:1083B00074790044617461205061747465726E0058 -:1083C000547820466C6F7720436F6E74726F6C0028 -:1083D000506F7274204E756D6265720035300037D3 -:1083E0003500313130003133342E35003135300035 -:1083F00032303000333030003630300031323030FF -:10840000003138303000323030300032343030001B -:1084100033363030003438303000373230300039C5 -:108420003630300031392C3230300033382C343093 -:10843000300035362C3030300035372C36303000B7 -:1084400036342C3030300037362C38303000313173 -:10845000352C323030003720626974730038206266 -:1084600069747300312073746F7020626974003115 -:108470002E352073746F702062697473003220731C -:10848000746F702062697473006E6F20706172691E -:108490007479006F64642070617269747900657624 -:1084A000656E207061726974790073706163652014 -:1084B000706172697479006D61726B2070617269AC -:1084C000747900436F6C756D6E7300426172626502 -:1084D0007220506F6C650055555555552E2E2E0047 -:1084E0004E6F6E6500586F6E2F586F66660043546E -:1084F00053005072657373208020666F72206D6523 -:108500006E750028636F756E74696E672E2E2E2946 -:108510000000654E64204F6620436F4465000000F4 -:10852000000000000000000000000000000000004B -:10853000000000000000000000000000000000003B -:10854000000000000000000000000000000000002B -:10855000000000000000000000000000000000001B -:10856000000000000000000000000000000000000B -:1085700000000000000000000000000000000000FB -:1085800000000000000000000000000000000000EB -:1085900000000000000000000000000000000000DB -:1085A00000000000000000000000000000000000CB -:1085B00000000000000000000000000000000000BB -:1085C00000000000000000000000000000000000AB -:1085D000000000000000000000000000000000009B -:1085E000000000000000000000000000000000008B -:1085F000000000000000000000000000000000007B -:00000001FF -/* Intelliport II loadware */ -/* -31232 bytes read from ff.lod */ -- cgit v0.10.2 From c61307a7cc1be87b6785dad0885492b6ca7998db Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 9 Aug 2012 08:38:43 +0200 Subject: gpio: Fix debug message in of_get_named_gpio_flags() This was probably missed in the conversion done in commit 3d0f7cf ("gpio: Adjust of_xlate API to support multiple GPIO chips"). Signed-off-by: Thierry Reding Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index a18c4aa..f1a4599 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -82,7 +82,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); of_node_put(gg_data.gpiospec.np); - pr_debug("%s exited with status %d\n", __func__, ret); + pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio); return gg_data.out_gpio; } EXPORT_SYMBOL(of_get_named_gpio_flags); -- cgit v0.10.2 From 5d4121c04b3577e37e389b3553d442f44bb346d7 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 17 Aug 2012 14:27:52 +0200 Subject: TTY: check if tty->port is assigned And if not, complain loudly. None in-kernel module should trigger that, but let us find out for sure. On the other hand, all the out-of-tree modules will hit that. Give them some time (maybe one release) to catch up. Signed-off-by: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 28c3e86..41e42f1 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1415,6 +1415,10 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) if (!tty->port) tty->port = driver->ports[idx]; + WARN_RATELIMIT(!tty->port, + "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n", + __func__, tty->driver->name); + /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need -- cgit v0.10.2 From b7ca69289680cf631fb20b7d436467c4ec1153cd Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 3 Aug 2012 08:43:01 -0500 Subject: CIFS: Protect i_nlink from being negative that can cause warning messages. Pavel had initially suggested a smaller patch around drop_nlink, after a similar problem was discovered NFS. Protecting additional places where nlink is touched was suggested by Jeff Layton and is included in this. Reviewed-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Steve French diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7354877..cb79c7e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -124,10 +124,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) { struct cifsInodeInfo *cifs_i = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); - unsigned long oldtime = cifs_i->time; cifs_revalidate_cache(inode, fattr); + spin_lock(&inode->i_lock); inode->i_atime = fattr->cf_atime; inode->i_mtime = fattr->cf_mtime; inode->i_ctime = fattr->cf_ctime; @@ -148,9 +148,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) else cifs_i->time = jiffies; - cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode, - oldtime, cifs_i->time); - cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; cifs_i->server_eof = fattr->cf_eof; @@ -158,7 +155,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) * Can't safely change the file size here if the client is writing to * it due to potential races. */ - spin_lock(&inode->i_lock); if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { i_size_write(inode, fattr->cf_eof); @@ -859,12 +855,14 @@ struct inode *cifs_root_iget(struct super_block *sb) if (rc && tcon->ipc) { cFYI(1, "ipc connection - fake read inode"); + spin_lock(&inode->i_lock); inode->i_mode |= S_IFDIR; set_nlink(inode, 2); inode->i_op = &cifs_ipc_inode_ops; inode->i_fop = &simple_dir_operations; inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; + spin_unlock(&inode->i_lock); } else if (rc) { iget_failed(inode); inode = ERR_PTR(rc); @@ -1110,6 +1108,15 @@ undo_setattr: goto out_close; } +/* copied from fs/nfs/dir.c with small changes */ +static void +cifs_drop_nlink(struct inode *inode) +{ + spin_lock(&inode->i_lock); + if (inode->i_nlink > 0) + drop_nlink(inode); + spin_unlock(&inode->i_lock); +} /* * If dentry->d_inode is null (usually meaning the cached dentry @@ -1166,13 +1173,13 @@ retry_std_delete: psx_del_no_retry: if (!rc) { if (inode) - drop_nlink(inode); + cifs_drop_nlink(inode); } else if (rc == -ENOENT) { d_drop(dentry); } else if (rc == -ETXTBSY) { rc = cifs_rename_pending_delete(full_path, dentry, xid); if (rc == 0) - drop_nlink(inode); + cifs_drop_nlink(inode); } else if ((rc == -EACCES) && (dosattr == 0) && inode) { attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); if (attrs == NULL) { @@ -1241,9 +1248,10 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode, * setting nlink not necessary except in cases where we failed to get it * from the server or was set bogus */ + spin_lock(&dentry->d_inode->i_lock); if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2)) set_nlink(dentry->d_inode, 2); - + spin_unlock(&dentry->d_inode->i_lock); mode &= ~current_umask(); /* must turn on setgid bit if parent dir has it */ if (inode->i_mode & S_ISGID) diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 09e4b3a..e6ce3b1 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -433,7 +433,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, if (old_file->d_inode) { cifsInode = CIFS_I(old_file->d_inode); if (rc == 0) { + spin_lock(&old_file->d_inode->i_lock); inc_nlink(old_file->d_inode); + spin_unlock(&old_file->d_inode->i_lock); /* BB should we make this contingent on superblock flag NOATIME? */ /* old_file->d_inode->i_ctime = CURRENT_TIME;*/ /* parent dir timestamps will update from srv -- cgit v0.10.2 From 7411286088d5ba879e9ffcaaa296f657642ef2c4 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 27 Jul 2012 01:20:41 +0400 Subject: CIFS: Fix log messages in packet checking for SMB2 Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index a4ff5d5..e4d3b99 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -52,7 +52,8 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid) cERROR(1, "Bad protocol string signature header %x", *(unsigned int *) hdr->ProtocolId); if (mid != hdr->MessageId) - cERROR(1, "Mids do not match"); + cERROR(1, "Mids do not match: %llu and %llu", mid, + hdr->MessageId); } cERROR(1, "Bad SMB detected. The Mid=%llu", hdr->MessageId); return 1; @@ -107,7 +108,7 @@ smb2_check_message(char *buf, unsigned int length) * ie Validate the wct via smb2_struct_sizes table above */ - if (length < 2 + sizeof(struct smb2_hdr)) { + if (length < sizeof(struct smb2_pdu)) { if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) { pdu->StructureSize2 = 0; /* @@ -121,15 +122,15 @@ smb2_check_message(char *buf, unsigned int length) return 1; } if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) { - cERROR(1, "SMB length greater than maximum, mid=%lld", mid); + cERROR(1, "SMB length greater than maximum, mid=%llu", mid); return 1; } if (check_smb2_hdr(hdr, mid)) return 1; - if (hdr->StructureSize != SMB2_HEADER_SIZE) { - cERROR(1, "Illegal structure size %d", + if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) { + cERROR(1, "Illegal structure size %u", le16_to_cpu(hdr->StructureSize)); return 1; } @@ -161,8 +162,9 @@ smb2_check_message(char *buf, unsigned int length) if (4 + len != clc_len) { cFYI(1, "Calculated size %u length %u mismatch mid %llu", clc_len, 4 + len, mid); - if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */ - return 0; /* BB workaround Samba 3 bug SessSetup rsp */ + /* server can return one byte more */ + if (clc_len == 4 + len + 1) + return 0; return 1; } return 0; diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index f37a1b4..c5fbfac 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -87,10 +87,6 @@ #define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe) -#define SMB2_HEADER_SIZE __constant_le16_to_cpu(64) - -#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9) - /* * SMB2 Header Definition * @@ -99,6 +95,9 @@ * "PDU" : "Protocol Data Unit" (ie a network "frame") * */ + +#define SMB2_HEADER_STRUCTURE_SIZE __constant_le16_to_cpu(64) + struct smb2_hdr { __be32 smb2_buf_length; /* big endian on wire */ /* length is only two or three bytes - with @@ -140,6 +139,9 @@ struct smb2_pdu { * command code name for the struct. Note that structures must be packed. * */ + +#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9) + struct smb2_err_rsp { struct smb2_hdr hdr; __le16 StructureSize; -- cgit v0.10.2 From 985e4ff016b5f3d95c12fe8073d1df89300dab3d Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 3 Aug 2012 09:42:45 -0500 Subject: cifs: print error code if smb signature verification fails While trying to debug a SMB signature related issue with Windows Servers figured out it might be easier to debug if we print the error code from cifs_verify_signature(). Also, fix indendation while at it. Signed-off-by: Suresh Jayaraman Reviewed-by: Jeff Layton Signed-off-by: Steve French diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 074923c..f0cf934 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1576,9 +1576,14 @@ cifs_readv_callback(struct mid_q_entry *mid) /* result already set, check signature */ if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { - if (cifs_verify_signature(rdata->iov, rdata->nr_iov, - server, mid->sequence_number + 1)) - cERROR(1, "Unexpected SMB signature"); + int rc = 0; + + rc = cifs_verify_signature(rdata->iov, rdata->nr_iov, + server, + mid->sequence_number + 1); + if (rc) + cERROR(1, "SMB signature verification returned " + "error = %d", rc); } /* FIXME: should this be counted toward the initiating task? */ task_io_account_read(rdata->bytes); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 83867ef..d9b639b 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -503,13 +503,16 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, /* convert the length into a more usable form */ if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { struct kvec iov; + int rc = 0; iov.iov_base = mid->resp_buf; iov.iov_len = len; /* FIXME: add code to kill session */ - if (cifs_verify_signature(&iov, 1, server, - mid->sequence_number + 1) != 0) - cERROR(1, "Unexpected SMB signature"); + rc = cifs_verify_signature(&iov, 1, server, + mid->sequence_number + 1); + if (rc) + cERROR(1, "SMB signature verification returned error = " + "%d", rc); } /* BB special case reconnect tid and uid here? */ -- cgit v0.10.2 From ea7b4887e7266b93fa0c203cc452a926a0fef4f0 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 17 Aug 2012 18:02:19 +0400 Subject: CIFS: Fix cifs_do_create error hadnling Commit d2c127197dfc0b2bae62a52e1e0d3e3ff493919e caused a regression in cifs_do_create error handling. Fix this by closing a file handle in the case of a get_inode_info(_unix) error. Also remove unnecessary checks for newinode being NULL. Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index cbe709a..781025b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -356,19 +356,12 @@ cifs_create_get_file_info: cifs_create_set_dentry: if (rc != 0) { cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); + CIFSSMBClose(xid, tcon, *fileHandle); goto out; } d_drop(direntry); d_add(direntry, newinode); - /* ENOENT for create? How weird... */ - rc = -ENOENT; - if (!newinode) { - CIFSSMBClose(xid, tcon, *fileHandle); - goto out; - } - rc = 0; - out: kfree(buf); kfree(full_path); -- cgit v0.10.2 From 2dba62c30ec3040ef1b647a8976fd7e6854cc7a7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sun, 19 Aug 2012 10:16:08 +0000 Subject: netfilter: nfnetlink_log: fix NLA_PUT macro removal bug Commit 1db20a52 (nfnetlink_log: Stop using NLA_PUT*().) incorrectly converted a NLA_PUT_BE16 macro to nla_put_be32() in nfnetlink_log: - NLA_PUT_BE16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)); + if (nla_put_be32(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 169ab59..592091c1 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -480,7 +480,7 @@ __build_packet_message(struct nfulnl_instance *inst, } if (indev && skb_mac_header_was_set(skb)) { - if (nla_put_be32(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) || + if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) || nla_put_be16(inst->skb, NFULA_HWLEN, htons(skb->dev->hard_header_len)) || nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len, -- cgit v0.10.2 From 3a245cbef6a9e4398456bd733b0b4b7cb3f11994 Mon Sep 17 00:00:00 2001 From: Thomas Huehn Date: Wed, 15 Aug 2012 22:48:35 +0200 Subject: ath5k: fix wrong max power per rate eeprom reads for 802.11a This patch reduces the per rate target power eeprom reads for AR5K_EEPROM_MODE_11A from 10 to 8, as there are only 8 valid power curve entries on the eeprom. The former 10 reads lead to equal max power limits per rate and this causes an increasing distortion for all rates above 24 MBit and leads to a needless poor performance in 802.11a mode. Signed-off-by: Thomas Huehn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 4026c90..b7e0258 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -1482,7 +1482,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) case AR5K_EEPROM_MODE_11A: offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); rate_pcal_info = ee->ee_rate_tpwr_a; - ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_RATE_CHAN; break; case AR5K_EEPROM_MODE_11B: offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h index dc2bcfe..94a9bbe 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.h +++ b/drivers/net/wireless/ath/ath5k/eeprom.h @@ -182,6 +182,7 @@ #define AR5K_EEPROM_EEP_DELTA 10 #define AR5K_EEPROM_N_MODES 3 #define AR5K_EEPROM_N_5GHZ_CHAN 10 +#define AR5K_EEPROM_N_5GHZ_RATE_CHAN 8 #define AR5K_EEPROM_N_2GHZ_CHAN 3 #define AR5K_EEPROM_N_2GHZ_CHAN_2413 4 #define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4 -- cgit v0.10.2 From 7b4e6cfbae304177b8edc0c12341b4896cab3f2d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 19 Aug 2012 11:49:58 +0200 Subject: drivers/net/wireless/ipw2x00/ipw2100.c: introduce missing initialization The result of one call to a function is tested, and then at the second call to the same function, the previous result, and not the current result, is tested again. Also changed &bssid to bssid, at the suggestion of Stanislav Yakovlev. The semantic match that finds the first problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression ret; identifier f; statement S1,S2; @@ *ret = f(...); if (\(ret != 0\|ret < 0\|ret == NULL\)) S1 ... when any *f(...); if (\(ret != 0\|ret < 0\|ret == NULL\)) S2 // Signed-off-by: Julia Lawall Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 95aa8e1..83324b3 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -2042,7 +2042,8 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) return; } len = ETH_ALEN; - ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len); + ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid, + &len); if (ret) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", __LINE__); -- cgit v0.10.2 From 94543a8d4fb302817014981489f15cb3b92ec3c2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Aug 2012 18:57:10 +0200 Subject: iwlwifi: fix flow handler debug code iwl_dbgfs_fh_reg_read() can cause crashes and/or BUG_ON in slub because the ifdefs are wrong, the code in iwl_dump_fh() should use DEBUGFS, not DEBUG to protect the buffer writing code. Also, while at it, clean up the arguments to the function, some code and make it generally safer. Cc: stable@vger.kernel.org Reported-by: Benjamin Herrenschmidt Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index d9694c5..4ffc18d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -350,7 +350,7 @@ int iwl_queue_space(const struct iwl_queue *q); /***************************************************** * Error handling ******************************************************/ -int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display); +int iwl_dump_fh(struct iwl_trans *trans, char **buf); void iwl_dump_csr(struct iwl_trans *trans); /***************************************************** diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 39a6ca1..d1a61ba 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -555,7 +555,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans) } iwl_dump_csr(trans); - iwl_dump_fh(trans, NULL, false); + iwl_dump_fh(trans, NULL); iwl_op_mode_nic_error(trans->op_mode); } diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 939c2f7..1e86ea2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1649,13 +1649,9 @@ static const char *get_fh_string(int cmd) #undef IWL_CMD } -int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display) +int iwl_dump_fh(struct iwl_trans *trans, char **buf) { int i; -#ifdef CONFIG_IWLWIFI_DEBUG - int pos = 0; - size_t bufsz = 0; -#endif static const u32 fh_tbl[] = { FH_RSCSR_CHNL0_STTS_WPTR_REG, FH_RSCSR_CHNL0_RBDCB_BASE_REG, @@ -1667,29 +1663,35 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display) FH_TSSR_TX_STATUS_REG, FH_TSSR_TX_ERROR_REG }; -#ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (buf) { + int pos = 0; + size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; + *buf = kmalloc(bufsz, GFP_KERNEL); if (!*buf) return -ENOMEM; + pos += scnprintf(*buf + pos, bufsz - pos, "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) pos += scnprintf(*buf + pos, bufsz - pos, " %34s: 0X%08x\n", get_fh_string(fh_tbl[i]), iwl_read_direct32(trans, fh_tbl[i])); - } + return pos; } #endif + IWL_ERR(trans, "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) IWL_ERR(trans, " %34s: 0X%08x\n", get_fh_string(fh_tbl[i]), iwl_read_direct32(trans, fh_tbl[i])); - } + return 0; } @@ -1982,11 +1984,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_trans *trans = file->private_data; - char *buf; + char *buf = NULL; int pos = 0; ssize_t ret = -EFAULT; - ret = pos = iwl_dump_fh(trans, &buf, true); + ret = pos = iwl_dump_fh(trans, &buf); if (buf) { ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); -- cgit v0.10.2 From 4fc79db178f0a0ede479b4713e00df2d106028b3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 21 Aug 2012 18:57:11 +0200 Subject: iwlwifi: protect SRAM debugfs If the device is not started, we can't read its SRAM and attempting to do so will cause issues. Protect the debugfs read. Cc: stable@vger.kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index 46782f1..a47b306 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -124,6 +124,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, const struct fw_img *img; size_t bufsz; + if (!iwl_is_ready_rf(priv)) + return -EAGAIN; + /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { priv->dbgfs_sram_offset = 0x800000; -- cgit v0.10.2 From 4f9c1397e2e80e52b17ec4e39760caa807bd15c7 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Wed, 8 Aug 2012 09:07:38 +0800 Subject: PCI/PM: Enable D3/D3cold by default for most devices This patch fixes the following bug: http://marc.info/?l=linux-usb&m=134318961120825&w=2 Originally, device lower power states include D1, D2, D3. After that, D3 is further divided into D3hot and D3cold. To support both scenario safely, original D3 is mapped to D3cold. When adding D3cold support, because worry about some device may have broken D3cold support, D3cold is disabled by default. This disable D3 on original platform too. But some original platform may only have working D3, but no working D1, D2. The root cause of the above bug is it too. To deal with this, this patch enables D3/D3cold by default for most devices. This restores the original behavior. For some devices that suspected to have broken D3cold support, such as PCIe port, D3cold is disabled by default. Reported-by: Bjorn Mork Signed-off-by: Huang Ying Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f3ea977..ab4bf5a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1941,6 +1941,7 @@ void pci_pm_init(struct pci_dev *dev) dev->pm_cap = pm; dev->d3_delay = PCI_PM_D3_WAIT; dev->d3cold_delay = PCI_PM_D3COLD_WAIT; + dev->d3cold_allowed = true; dev->d1_support = false; dev->d2_support = false; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 3a7eefc..62f5a76 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -200,6 +200,11 @@ static int __devinit pcie_portdrv_probe(struct pci_dev *dev, return status; pci_save_state(dev); + /* + * D3cold may not work properly on some PCIe port, so disable + * it by default. + */ + dev->d3cold_allowed = false; if (!pci_match_id(port_runtime_pm_black_list, dev)) pm_runtime_put_noidle(&dev->dev); -- cgit v0.10.2 From ea8c88f13d9fb1d6b39a05bfa07ae076ca1c6803 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Wed, 8 Aug 2012 09:07:39 +0800 Subject: PCI/PM: Keep parent bridge active when probing device This patch fixes the following bug: http://marc.info/?l=linux-pci&m=134329923124234&w=2 The root cause of the bug is as follow. If a device is not bound with the corresponding driver, the device runtime PM will be disabled and the device will be put into suspended state. So that, the bridge/PCIe port connected to it may be put into suspended and low power state. When do probing for the device later, because the bridge/PCIe port connected to it is in low power state, the IO access to device may fail. To solve the issue, the bridge/PCIe port connected to the device is put into active state before probing. Reported-by: Bjorn Mork Signed-off-by: Huang Ying Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 5270f1a..d6fd6b6 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -280,8 +280,12 @@ static long local_pci_probe(void *_ddi) { struct drv_dev_and_id *ddi = _ddi; struct device *dev = &ddi->dev->dev; + struct device *parent = dev->parent; int rc; + /* The parent bridge must be in active state when probing */ + if (parent) + pm_runtime_get_sync(parent); /* Unbound PCI devices are always set to disabled and suspended. * During probe, the device is set to enabled and active and the * usage count is incremented. If the driver supports runtime PM, @@ -298,6 +302,8 @@ static long local_pci_probe(void *_ddi) pm_runtime_set_suspended(dev); pm_runtime_put_noidle(dev); } + if (parent) + pm_runtime_put(parent); return rc; } -- cgit v0.10.2 From 3d8387efe1ad9eb5bfe8a2e58cdbd1b88b247eef Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Wed, 15 Aug 2012 09:43:03 +0800 Subject: PCI/PM: Fix config reg access for D3cold and bridge suspending This patch fixes the following bug: http://marc.info/?l=linux-pci&m=134338059022620&w=2 Where lspci does not work properly if a device and the corresponding parent bridge (such as PCIe port) is suspended. This is because the device configuration space registers will be not accessible if the corresponding parent bridge is suspended or the device is put into D3cold state. To solve the issue, the bridge/PCIe port connected to the device is put into active state before read/write configuration space registers. If the device is in D3cold state, it will be put into active state too. To avoid resume/suspend PCIe port for each configuration register read/write, a small delay is added before the PCIe port to go suspended. Reported-by: Bjorn Mork Signed-off-by: Huang Ying Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 6869009..02d107b 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -458,6 +458,40 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) } struct device_attribute vga_attr = __ATTR_RO(boot_vga); +static void +pci_config_pm_runtime_get(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + + if (parent) + pm_runtime_get_sync(parent); + pm_runtime_get_noresume(dev); + /* + * pdev->current_state is set to PCI_D3cold during suspending, + * so wait until suspending completes + */ + pm_runtime_barrier(dev); + /* + * Only need to resume devices in D3cold, because config + * registers are still accessible for devices suspended but + * not in D3cold. + */ + if (pdev->current_state == PCI_D3cold) + pm_runtime_resume(dev); +} + +static void +pci_config_pm_runtime_put(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct device *parent = dev->parent; + + pm_runtime_put(dev); + if (parent) + pm_runtime_put_sync(parent); +} + static ssize_t pci_read_config(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, @@ -484,6 +518,8 @@ pci_read_config(struct file *filp, struct kobject *kobj, size = count; } + pci_config_pm_runtime_get(dev); + if ((off & 1) && size) { u8 val; pci_user_read_config_byte(dev, off, &val); @@ -529,6 +565,8 @@ pci_read_config(struct file *filp, struct kobject *kobj, --size; } + pci_config_pm_runtime_put(dev); + return count; } @@ -549,6 +587,8 @@ pci_write_config(struct file* filp, struct kobject *kobj, count = size; } + pci_config_pm_runtime_get(dev); + if ((off & 1) && size) { pci_user_write_config_byte(dev, off, data[off - init_off]); off++; @@ -587,6 +627,8 @@ pci_write_config(struct file* filp, struct kobject *kobj, --size; } + pci_config_pm_runtime_put(dev); + return count; } diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 62f5a76..e76b447 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -140,9 +140,17 @@ static int pcie_port_runtime_resume(struct device *dev) { return 0; } + +static int pcie_port_runtime_idle(struct device *dev) +{ + /* Delay for a short while to prevent too frequent suspend/resume */ + pm_schedule_suspend(dev, 10); + return -EBUSY; +} #else #define pcie_port_runtime_suspend NULL #define pcie_port_runtime_resume NULL +#define pcie_port_runtime_idle NULL #endif static const struct dev_pm_ops pcie_portdrv_pm_ops = { @@ -155,6 +163,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = { .resume_noirq = pcie_port_resume_noirq, .runtime_suspend = pcie_port_runtime_suspend, .runtime_resume = pcie_port_runtime_resume, + .runtime_idle = pcie_port_runtime_idle, }; #define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) -- cgit v0.10.2 From 046c6531b60e8b9eabf47820a06161338a612167 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Wed, 8 Aug 2012 09:07:41 +0800 Subject: PCI/PM: Add ABI document for sysfs file d3cold_allowed This patch adds ABI document for the following sysfs file: /sys/bus/pci/devices/.../d3cold_allowed Signed-off-by: Huang Ying Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 34f5110..dff1f48 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -210,3 +210,15 @@ Users: firmware assigned instance number of the PCI device that can help in understanding the firmware intended order of the PCI device. + +What: /sys/bus/pci/devices/.../d3cold_allowed +Date: July 2012 +Contact: Huang Ying +Description: + d3cold_allowed is bit to control whether the corresponding PCI + device can be put into D3Cold state. If it is cleared, the + device will never be put into D3Cold state. If it is set, the + device may be put into D3Cold state if other requirements are + satisfied too. Reading this attribute will show the current + value of d3cold_allowed bit. Writing this attribute will set + the value of d3cold_allowed bit. -- cgit v0.10.2 From a1d0fa776870aeda5eb91b131d0f1aede6d94ef1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 21 Aug 2012 22:01:45 -0700 Subject: Input: edt-ft5x06 - fix build error when compiling wthout CONFIG_DEBUG_FS This fixes the following breakage: edt-ft5x06.c: In function edt_ft5x06_ts_remove: edt-ft5x06.c:846:14: error: struct edt_ft5x06_ts_data has no member named raw_buffer Signed-off-by: Guenter Roeck Acked-by: Simon Budig Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 9afc777..b06a5e3 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -602,6 +602,7 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) { if (tsdata->debug_dir) debugfs_remove_recursive(tsdata->debug_dir); + kfree(tsdata->raw_buffer); } #else @@ -843,7 +844,6 @@ static int __devexit edt_ft5x06_ts_remove(struct i2c_client *client) if (gpio_is_valid(pdata->reset_pin)) gpio_free(pdata->reset_pin); - kfree(tsdata->raw_buffer); kfree(tsdata); return 0; -- cgit v0.10.2 From f35dd69ba341bda3790713b9e964483934b995e1 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 21 Aug 2012 21:57:15 -0700 Subject: Input: imx_keypad - reset the hardware before enabling Ensure the hardware is correctly initialized before requesting the interrupt, otherwise if a key was already touched since power-on the kernel enters an interrupt loop. To fix this issue we clear pending interrupt sources. We also have to make sure clk is enabled while changing the keypad registers. Signed-off-by: Michael Grzeschik Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index ff4c0a8..ce68e36 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -358,6 +358,7 @@ static void imx_keypad_inhibit(struct imx_keypad *keypad) /* Inhibit KDI and KRI interrupts. */ reg_val = readw(keypad->mmio_base + KPSR); reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE); + reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD; writew(reg_val, keypad->mmio_base + KPSR); /* Colums as open drain and disable all rows */ @@ -515,7 +516,9 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev) input_set_drvdata(input_dev, keypad); /* Ensure that the keypad will stay dormant until opened */ + clk_enable(keypad->clk); imx_keypad_inhibit(keypad); + clk_disable(keypad->clk); error = request_irq(irq, imx_keypad_irq_handler, 0, pdev->name, keypad); -- cgit v0.10.2 From 7b125b94ca16b7e618c6241cb02c4c8060cea5e3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 21 Aug 2012 21:57:15 -0700 Subject: Input: i8042 - add Gigabyte T1005 series netbooks to noloop table They all define their chassis type as "Other" and therefore are not categorized as "laptops" by the driver, which tries to perform AUX IRQ delivery test which fails and causes touchpad not working. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42620 Cc: stable@kernel.org Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 5ec774d..6918773 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -177,6 +177,20 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { }, }, { + /* Gigabyte T1005 - defines wrong chassis type ("Other") */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "T1005"), + }, + }, + { + /* Gigabyte T1005M/P - defines wrong chassis type ("Other") */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), + DMI_MATCH(DMI_PRODUCT_NAME, "T1005M/P"), + }, + }, + { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv9700"), -- cgit v0.10.2 From 6f4d0382e2a6d27045e223d8c452659477826650 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 21 Aug 2012 22:11:59 -0700 Subject: Input: wacom - add support for EMR on Cintiq 24HD touch Adds support for the EMR digitizer on the Cintiq 24HD touch. The EMR digitizer should work identically to that found on the Cintiq 24HD. The touch digitizer is a separate USB device similar to how we split apart some other devices. Signed-off-by: Jason Gerecke Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 0020419..532d067 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1848,7 +1848,10 @@ static const struct wacom_features wacom_features_0x2A = { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xF4 = - { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, + { "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, + 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0xF8 = + { "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0x3F = { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, @@ -2091,6 +2094,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xEF) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_WACOM(0xF4) }, + { USB_DEVICE_WACOM(0xF8) }, { USB_DEVICE_WACOM(0xFA) }, { USB_DEVICE_LENOVO(0x6004) }, { } -- cgit v0.10.2 From 27f011243a6e4e8b81078df1d83608dae31e3d38 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 20 Aug 2012 11:28:25 -0700 Subject: mac80211: fix DS to MBSS address translation The destination address of unicast frames forwarded through a mesh gate was being replaced with the broadcast address. Instead leave the original destination address as the mesh DA. If the nexthop address is not in the mpath table it will be resolved. If that fails, the frame will be forwarded to known mesh gates. Reported-by: Cedric Voncken Signed-off-by: Thomas Pedersen Signed-off-by: Johannes Berg diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index acf712f..c5e8c9c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1811,37 +1811,31 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, NULL, NULL); } else { - int is_mesh_mcast = 1; - const u8 *mesh_da; + /* DS -> MBSS (802.11-2012 13.11.3.3). + * For unicast with unknown forwarding information, + * destination might be in the MBSS or if that fails + * forwarded to another mesh gate. In either case + * resolution will be handled in ieee80211_xmit(), so + * leave the original DA. This also works for mcast */ + const u8 *mesh_da = skb->data; + + if (mppath) + mesh_da = mppath->mpp; + else if (mpath) + mesh_da = mpath->dst; + rcu_read_unlock(); - if (is_multicast_ether_addr(skb->data)) - /* DA TA mSA AE:SA */ - mesh_da = skb->data; - else { - static const u8 bcast[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - if (mppath) { - /* RA TA mDA mSA AE:DA SA */ - mesh_da = mppath->mpp; - is_mesh_mcast = 0; - } else if (mpath) { - mesh_da = mpath->dst; - is_mesh_mcast = 0; - } else { - /* DA TA mSA AE:SA */ - mesh_da = bcast; - } - } hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc, mesh_da, sdata->vif.addr); - rcu_read_unlock(); - if (is_mesh_mcast) + if (is_multicast_ether_addr(mesh_da)) + /* DA TA mSA AE:SA */ meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, skb->data + ETH_ALEN, NULL); else + /* RA TA mDA mSA AE:DA SA */ meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata, -- cgit v0.10.2 From 6c0274cbe63ec265f842537825684a619e6cce93 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 22 Aug 2012 12:13:48 +0200 Subject: ARM: shmobile: sh73a0: fixup RELOC_BASE of intca_irq_pins_desc sh73a0 :: intca_irq_pins_desc irq table had conflict from irq 552 to irq 557 before. But the second controller was simply trampling the first one by way of the -EEXIST case from irq_alloc_desc_at(). But now, we have irqdomain support from 1d6a21b0a672fb29b01ccf397d478e0541e17716 (sh: intc: initial irqdomain support) The irqdomain code has simply tightened down the sanity checks and error path. So, sh73a0 CPU board got some WARNING when booting now. This patch fixup RELOC_BASE to solve this issue. Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Rafael J. Wysocki diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index ee44740..588555a 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -259,9 +259,9 @@ static int sh73a0_set_wake(struct irq_data *data, unsigned int on) return 0; /* always allow wakeup */ } -#define RELOC_BASE 0x1000 +#define RELOC_BASE 0x1200 -/* INTCA IRQ pins at INTCS + 0x1000 to make space for GIC+INTC handling */ +/* INTCA IRQ pins at INTCS + RELOC_BASE to make space for GIC+INTC handling */ #define INTCS_VECT_RELOC(n, vect) INTCS_VECT((n), (vect) + RELOC_BASE) INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000, -- cgit v0.10.2 From 042b92c185cbd7b4291710255510ae76b2d7797b Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 22 Aug 2012 16:10:43 +0200 Subject: ALSA: hda - Do not set GPIOs for speakers on IDT if there are no speakers This fixes an issue with a machine where there were no speakers, but GPIO0 had to be data=1 for the headphone to be functioning. I'm not sure if we need a more advanced patch to solve all possible cases, but if so, this patch would still provide a minor optimisation. BugLink: https://bugs.launchpad.net/bugs/1040077 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ea5775a..3edd73c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4543,6 +4543,9 @@ static void stac92xx_line_out_detect(struct hda_codec *codec, struct auto_pin_cfg *cfg = &spec->autocfg; int i; + if (cfg->speaker_outs == 0) + return; + for (i = 0; i < cfg->line_outs; i++) { if (presence) break; -- cgit v0.10.2 From ea2d218308e5710c70d76eb3c2876988c88119cc Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Sun, 5 Aug 2012 00:29:07 +0300 Subject: brcm80211: smac: set interface down on reset This change marks interface as down on reset, otherwise the driver can't reinitialize itself properly. Without the change a transient problem turns out to be critical and leads to inavailability to reset the driver without brcmsmac module unload/load cycle: ieee80211 phy0: wl0: PSM microcode watchdog fired at 5993 (seconds). Resetting. brcms_c_dpc : PSM Watchdog, chipid 0xa8d9, chiprev 0x1 ieee80211 phy0: wl0: fatal error, reinitializing ieee80211 phy0: Hardware restart was requested ieee80211 phy0: brcms_ops_start: brcms_up() returned -19 Signed-off-by: Vladimir Zapolskiy Cc: Arend van Spriel Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 192ad5c..a5edebe 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1233,6 +1233,9 @@ uint brcms_reset(struct brcms_info *wl) /* dpc will not be rescheduled */ wl->resched = false; + /* inform publicly that interface is down */ + wl->pub->up = false; + return 0; } -- cgit v0.10.2 From 9b04f350057863d1fad1ba071e09362a1da3503e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Aug 2012 20:48:29 +0000 Subject: ipv4: properly update pmtu Sylvain Munault reported following info : - TCP connection get "stuck" with data in send queue when doing "large" transfers ( like typing 'ps ax' on a ssh connection ) - Only happens on path where the PMTU is lower than the MTU of the interface - Is not present right after boot, it only appears 10-20min after boot or so. (and that's inside the _same_ TCP connection, it works fine at first and then in the same ssh session, it'll get stuck) - Definitely seems related to fragments somehow since I see a router sending ICMP message saying fragmentation is needed. - Exact same setup works fine with kernel 3.5.1 Problem happens when the 10 minutes (ip_rt_mtu_expires) expiration period is over. ip_rt_update_pmtu() calls dst_set_expires() to rearm a new expiration, but dst_set_expires() does nothing because dst.expires is already set. It seems we want to set the expires field to a new value, regardless of prior one. With help from Julian Anastasov. Reported-by: Sylvain Munaut Signed-off-by: Eric Dumazet CC: Julian Anastasov Tested-by: Sylvain Munaut Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index fd9ecb5..8c8c748 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -956,7 +956,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, dst->obsolete = DST_OBSOLETE_KILL; } else { rt->rt_pmtu = mtu; - dst_set_expires(&rt->dst, ip_rt_mtu_expires); + rt->dst.expires = max(1UL, jiffies + ip_rt_mtu_expires); } } -- cgit v0.10.2 From 5f42f7bc9638a0bc69dcb8b8b6da542b72113fc2 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 22 Aug 2012 00:26:15 +0000 Subject: stmmac: fix GMAC syn ID Erroneously the DWMAC_CORE_3_40 was set to 34 instead of 0x34. This can generate problems when run on old chips because the driver assumes that there are the extra 16 regs available for perfect filtering. Signed-off-by: Giuseppe Cavallaro Cc: Gianni Antoniazzi Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index f90fcb5..b4c44a5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -229,6 +229,6 @@ enum rtc_control { #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 /* Synopsys Core versions */ -#define DWMAC_CORE_3_40 34 +#define DWMAC_CORE_3_40 0x34 extern const struct stmmac_dma_ops dwmac1000_dma_ops; -- cgit v0.10.2 From a6b9650108003e994770209fb8efedf6e214dcf7 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Wed, 22 Aug 2012 00:26:16 +0000 Subject: stmmac: fix a typo in the macro used to mask the mmc irq This patch fixes the name of the macro used to mask the mmc interrupt: erroneously it was used: MMC_DEFAUL_MASK. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index c07cfe9..0c74a70 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c @@ -33,7 +33,7 @@ #define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */ #define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */ #define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */ -#define MMC_DEFAUL_MASK 0xffffffff +#define MMC_DEFAULT_MASK 0xffffffff /* MMC TX counter registers */ @@ -147,8 +147,8 @@ void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode) /* To mask all all interrupts.*/ void dwmac_mmc_intr_all_mask(void __iomem *ioaddr) { - writel(MMC_DEFAUL_MASK, ioaddr + MMC_RX_INTR_MASK); - writel(MMC_DEFAUL_MASK, ioaddr + MMC_TX_INTR_MASK); + writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK); + writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK); } /* This reads the MAC core counters (if actaully supported). -- cgit v0.10.2 From e432964a3c5ce517fd93101ae3875172ee958b65 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 24 Jul 2012 03:00:24 +0200 Subject: fbcon: prevent possible buffer overflow. Signed-off-by: Paul Cercueil Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 88e9204..fdefa8f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -449,7 +449,7 @@ static int __init fb_console_setup(char *this_opt) while ((options = strsep(&this_opt, ",")) != NULL) { if (!strncmp(options, "font:", 5)) - strcpy(fontname, options + 5); + strlcpy(fontname, options + 5, sizeof(fontname)); if (!strncmp(options, "scrollback:", 11)) { options += 11; -- cgit v0.10.2 From 72caa5fb948ef818fe1332848e9c61b10687ce7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Mon, 30 Jul 2012 21:09:49 +0200 Subject: fbcon: Fix bit_putcs() call to kmalloc(s, GFP_KERNEL) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to kmalloc(,GFP_ATOMIC) in bit_putcs to fix below trace: [ 9.771812] BUG: sleeping function called from invalid context at /usr/src/linux-git/mm/slub.c:943 [ 9.771814] in_atomic(): 1, irqs_disabled(): 1, pid: 1063, name: mount [ 9.771818] Pid: 1063, comm: mount Not tainted 3.5.0-jupiter-00003-g8d858b1-dirty #2 [ 9.771819] Call Trace: [ 9.771838] [] __might_sleep+0xcb/0xe0 [ 9.771844] [] __kmalloc+0xb4/0x1c0 [ 9.771851] [] ? queue_work+0x1a/0x30 [ 9.771854] [] ? queue_delayed_work+0xf/0x30 [ 9.771862] [] ? bit_putcs+0xf2/0x3e0 [ 9.771865] [] ? schedule_delayed_work+0x11/0x20 [ 9.771868] [] bit_putcs+0xf2/0x3e0 [ 9.771875] [] ? get_color.clone.14+0x28/0x100 [ 9.771878] [] fbcon_putcs+0x11f/0x130 [ 9.771882] [] ? bit_clear+0xe0/0xe0 [ 9.771885] [] fbcon_redraw.clone.21+0x11d/0x160 [ 9.771889] [] fbcon_scroll+0x79d/0xe10 [ 9.771892] [] ? get_color.clone.14+0x28/0x100 [ 9.771897] [] scrup+0x64/0xd0 [ 9.771900] [] lf+0x2b/0x60 [ 9.771903] [] vt_console_print+0x1d5/0x2f0 [ 9.771907] [] ? register_vt_notifier+0x20/0x20 [ 9.771913] [] call_console_drivers.clone.5+0xa5/0xc0 [ 9.771916] [] console_unlock+0x2fe/0x3c0 [ 9.771920] [] vprintk_emit+0x2e6/0x300 [ 9.771924] [] printk+0x38/0x3a [ 9.771931] [] reiserfs_remount+0x2ae/0x3e0 [ 9.771934] [] ? reiserfs_fill_super+0xb00/0xb00 [ 9.771939] [] do_remount_sb+0xab/0x150 [ 9.771943] [] ? ns_capable+0x46/0x70 [ 9.771948] [] do_mount+0x20c/0x6b0 [ 9.771955] [] ? strndup_user+0x34/0x50 [ 9.771958] [] sys_mount+0x6c/0xa0 [ 9.771964] [] sysenter_do_call+0x12/0x26 According to comment in bit_putcs() that kammloc() call only happens when fbcon is drawing to a monochrome framebuffer (which is my case with hid-picolcd). Signed-off-by: Bruno Prémont Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 28b1a83..61b182b 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -162,7 +162,7 @@ static void bit_putcs(struct vc_data *vc, struct fb_info *info, image.depth = 1; if (attribute) { - buf = kmalloc(cellsize, GFP_KERNEL); + buf = kmalloc(cellsize, GFP_ATOMIC); if (!buf) return; } -- cgit v0.10.2 From 01817d194a5c078696ac4a31b5d8b99a6a9e40c7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 4 Aug 2012 14:00:30 +0200 Subject: drivers/video/auo_k190x.c: drop kfree of devm_kzalloc's data Using kfree to free data allocated with devm_kzalloc causes double frees. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; @@ x = devm_kzalloc(...) ... ?-kfree(x); // Signed-off-by: Julia Lawall Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/auo_k190x.c b/drivers/video/auo_k190x.c index 77da6a2..c03ecdd 100644 --- a/drivers/video/auo_k190x.c +++ b/drivers/video/auo_k190x.c @@ -987,7 +987,6 @@ err_regfb: fb_dealloc_cmap(&info->cmap); err_cmap: fb_deferred_io_cleanup(info); - kfree(info->fbdefio); err_defio: vfree((void *)info->screen_base); err_irq: @@ -1022,7 +1021,6 @@ int __devexit auok190x_common_remove(struct platform_device *pdev) fb_dealloc_cmap(&info->cmap); fb_deferred_io_cleanup(info); - kfree(info->fbdefio); vfree((void *)info->screen_base); -- cgit v0.10.2 From 25682362564fa0c950d9afe798def2ec9c3676a2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 18 Aug 2012 18:55:41 +0300 Subject: video: mb862xxfb: prevent divide by zero bug Do a sanity check on these before using them as divisors. Signed-off-by: Dan Carpenter Acked-by: Anatolij Gustschin Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index 00ce1f3..57d940b 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -328,6 +328,8 @@ static int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd, case MB862XX_L1_SET_CFG: if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg))) return -EFAULT; + if (l1_cfg->dh == 0 || l1_cfg->dw == 0) + return -EINVAL; if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) { /* downscaling */ outreg(cap, GC_CAP_CSC, -- cgit v0.10.2 From 35d678664873041026171b4b5e1cec49299e33a0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 21 Aug 2012 09:09:47 +0300 Subject: OMAPDSS: Fix SDI PLL locking Commit f476ae9dab3234532d41d36beb4ba7be838fa786 (OMAPDSS: APPLY: Remove DISPC writes to manager's lcd parameters in interface) broke the SDI output, as it causes the SDI PLL locking to fail. LCLK and PCLK divisors are located in shadow registers, and we normally write them to DISPC registers when enabling the output. However, SDI uses pck-free as source clock for its PLL, and pck-free is affected by the divisors. And as we need the PLL before enabling the output, we need to write the divisors early. It seems just writing to the DISPC register is enough, and we don't need to care about the shadow register mechanism for pck-free. The exact reason for this is unknown. Signed-off-by: Tomi Valkeinen Reported-by: Aaro Koskinen Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 5d31699..f43bfe1 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -105,6 +105,20 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) sdi_config_lcd_manager(dssdev); + /* + * LCLK and PCLK divisors are located in shadow registers, and we + * normally write them to DISPC registers when enabling the output. + * However, SDI uses pck-free as source clock for its PLL, and pck-free + * is affected by the divisors. And as we need the PLL before enabling + * the output, we need to write the divisors early. + * + * It seems just writing to the DISPC register is enough, and we don't + * need to care about the shadow register mechanism for pck-free. The + * exact reason for this is unknown. + */ + dispc_mgr_set_clock_div(dssdev->manager->id, + &sdi.mgr_config.clock_info); + dss_sdi_init(dssdev->phy.sdi.datapairs); r = dss_sdi_enable(); if (r) -- cgit v0.10.2 From c1c52848cef52e157468b8879fc3cae23b6f3a99 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Tue, 21 Aug 2012 09:09:48 +0300 Subject: OMAPFB: fix framebuffer console colors omapfb does not currently set pseudo palette correctly for color depths above 16bpp, making red text invisible, command like echo -e '\e[0;31mRED' > /dev/tty1 will display nothing on framebuffer console in 24bpp mode. This is because temporary variable is declared incorrectly, fix it. Signed-off-by: Grazvydas Ignotas Cc: stable@vger.kernel.org # v3.x Signed-off-by: Tomi Valkeinen Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 08ec1a7..fc671d3 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1192,7 +1192,7 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, break; if (regno < 16) { - u16 pal; + u32 pal; pal = ((red >> (16 - var->red.length)) << var->red.offset) | ((green >> (16 - var->green.length)) << -- cgit v0.10.2 From 85ebea12f59e3341049a9c17edcb73fcf21043db Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 14 Aug 2012 11:19:21 +0200 Subject: ARM: at91: fix system timer irq issue due to sparse irq support AT91_ID_SYS as virq is incorrect because of spare irq support which introduces NR_IRQS_LEGACY offset. Signed-off-by: Ludovic Desroches Tested-by: Joachim Eastwood Signed-off-by: Nicolas Ferre diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c index 104ca40..aaa443b 100644 --- a/arch/arm/mach-at91/at91rm9200_time.c +++ b/arch/arm/mach-at91/at91rm9200_time.c @@ -197,7 +197,7 @@ void __init at91rm9200_timer_init(void) at91_st_read(AT91_ST_SR); /* Make IRQs happen for the system timer */ - setup_irq(AT91_ID_SYS, &at91rm9200_timer_irq); + setup_irq(NR_IRQS_LEGACY + AT91_ID_SYS, &at91rm9200_timer_irq); /* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used * directly for the clocksource and all clockevents, after adjusting -- cgit v0.10.2 From e402af6caa02f12ad213af2e22aa8a32970f99b0 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 14 Aug 2012 11:19:22 +0200 Subject: ARM: at91: fix rtc-at91sam9 irq issue due to sparse irq support AT91_ID_SYS as virq is incorrect because of spare irq support which introduces NR_IRQS_LEGACY offset. It modifies rtc-at91sam9 driver in order to get irq from resources. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 7b9c2ba..bce572a 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -726,6 +726,8 @@ static struct resource rtt_resources[] = { .flags = IORESOURCE_MEM, }, { .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, }, }; @@ -744,10 +746,12 @@ static void __init at91_add_device_rtt_rtc(void) * The second resource is needed: * GPBR will serve as the storage for RTC time offset */ - at91sam9260_rtt_device.num_resources = 2; + at91sam9260_rtt_device.num_resources = 3; rtt_resources[1].start = AT91SAM9260_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR; rtt_resources[1].end = rtt_resources[1].start + 3; + rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS; + rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS; } #else static void __init at91_add_device_rtt_rtc(void) diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 8df5c1b..bc2590d 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -609,6 +609,8 @@ static struct resource rtt_resources[] = { .flags = IORESOURCE_MEM, }, { .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, } }; @@ -626,10 +628,12 @@ static void __init at91_add_device_rtt_rtc(void) * The second resource is needed: * GPBR will serve as the storage for RTC time offset */ - at91sam9261_rtt_device.num_resources = 2; + at91sam9261_rtt_device.num_resources = 3; rtt_resources[1].start = AT91SAM9261_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR; rtt_resources[1].end = rtt_resources[1].start + 3; + rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS; + rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS; } #else static void __init at91_add_device_rtt_rtc(void) diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index eb6bbf8..9b6ca73 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -990,6 +990,8 @@ static struct resource rtt0_resources[] = { .flags = IORESOURCE_MEM, }, { .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, } }; @@ -1006,6 +1008,8 @@ static struct resource rtt1_resources[] = { .flags = IORESOURCE_MEM, }, { .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, } }; @@ -1027,14 +1031,14 @@ static void __init at91_add_device_rtt_rtc(void) * The second resource is needed only for the chosen RTT: * GPBR will serve as the storage for RTC time offset */ - at91sam9263_rtt0_device.num_resources = 2; + at91sam9263_rtt0_device.num_resources = 3; at91sam9263_rtt1_device.num_resources = 1; pdev = &at91sam9263_rtt0_device; r = rtt0_resources; break; case 1: at91sam9263_rtt0_device.num_resources = 1; - at91sam9263_rtt1_device.num_resources = 2; + at91sam9263_rtt1_device.num_resources = 3; pdev = &at91sam9263_rtt1_device; r = rtt1_resources; break; @@ -1047,6 +1051,8 @@ static void __init at91_add_device_rtt_rtc(void) pdev->name = "rtc-at91sam9"; r[1].start = AT91SAM9263_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR; r[1].end = r[1].start + 3; + r[2].start = NR_IRQS_LEGACY + AT91_ID_SYS; + r[2].end = NR_IRQS_LEGACY + AT91_ID_SYS; } #else static void __init at91_add_device_rtt_rtc(void) diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 0607399..1b47319 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -1293,6 +1293,8 @@ static struct resource rtt_resources[] = { .flags = IORESOURCE_MEM, }, { .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, } }; @@ -1310,10 +1312,12 @@ static void __init at91_add_device_rtt_rtc(void) * The second resource is needed: * GPBR will serve as the storage for RTC time offset */ - at91sam9g45_rtt_device.num_resources = 2; + at91sam9g45_rtt_device.num_resources = 3; rtt_resources[1].start = AT91SAM9G45_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR; rtt_resources[1].end = rtt_resources[1].start + 3; + rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS; + rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS; } #else static void __init at91_add_device_rtt_rtc(void) diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index f09fff9..b3d365d 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -688,6 +688,8 @@ static struct resource rtt_resources[] = { .flags = IORESOURCE_MEM, }, { .flags = IORESOURCE_MEM, + }, { + .flags = IORESOURCE_IRQ, } }; @@ -705,10 +707,12 @@ static void __init at91_add_device_rtt_rtc(void) * The second resource is needed: * GPBR will serve as the storage for RTC time offset */ - at91sam9rl_rtt_device.num_resources = 2; + at91sam9rl_rtt_device.num_resources = 3; rtt_resources[1].start = AT91SAM9RL_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR; rtt_resources[1].end = rtt_resources[1].start + 3; + rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS; + rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS; } #else static void __init at91_add_device_rtt_rtc(void) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 8318689..1dd61f4 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -58,6 +58,7 @@ struct sam9_rtc { struct rtc_device *rtcdev; u32 imr; void __iomem *gpbr; + int irq; }; #define rtt_readl(rtc, field) \ @@ -292,7 +293,7 @@ static int __devinit at91_rtc_probe(struct platform_device *pdev) { struct resource *r, *r_gpbr; struct sam9_rtc *rtc; - int ret; + int ret, irq; u32 mr; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -302,10 +303,18 @@ static int __devinit at91_rtc_probe(struct platform_device *pdev) return -ENODEV; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get interrupt resource\n"); + return irq; + } + rtc = kzalloc(sizeof *rtc, GFP_KERNEL); if (!rtc) return -ENOMEM; + rtc->irq = irq; + /* platform setup code should have handled this; sigh */ if (!device_can_wakeup(&pdev->dev)) device_init_wakeup(&pdev->dev, 1); @@ -345,11 +354,10 @@ static int __devinit at91_rtc_probe(struct platform_device *pdev) } /* register irq handler after we know what name we'll use */ - ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, - IRQF_SHARED, + ret = request_irq(rtc->irq, at91_rtc_interrupt, IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc); if (ret) { - dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); + dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); rtc_device_unregister(rtc->rtcdev); goto fail_register; } @@ -386,7 +394,7 @@ static int __devexit at91_rtc_remove(struct platform_device *pdev) /* disable all interrupts */ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); - free_irq(AT91_ID_SYS, rtc); + free_irq(rtc->irq, rtc); rtc_device_unregister(rtc->rtcdev); @@ -423,7 +431,7 @@ static int at91_rtc_suspend(struct platform_device *pdev, rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); if (rtc->imr) { if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) { - enable_irq_wake(AT91_ID_SYS); + enable_irq_wake(rtc->irq); /* don't let RTTINC cause wakeups */ if (mr & AT91_RTT_RTTINCIEN) rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); @@ -441,7 +449,7 @@ static int at91_rtc_resume(struct platform_device *pdev) if (rtc->imr) { if (device_may_wakeup(&pdev->dev)) - disable_irq_wake(AT91_ID_SYS); + disable_irq_wake(rtc->irq); mr = rtt_readl(rtc, MR); rtt_writel(rtc, MR, mr | rtc->imr); } -- cgit v0.10.2 From 2ed1f58900280f79485bbc15f781687bd9584675 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 9 Jul 2012 21:06:25 +0200 Subject: ARM: at91/clock: fix PLLA overclock warning Fix PLLA overclock warning in relation with datasheet numbers. Add new > 240 MHz and > 210 MHz SoC categories. Reported-by: Jiri Prchal Signed-off-by: Nicolas Ferre diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index de2ec6b..188c829 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -63,6 +63,12 @@ EXPORT_SYMBOL_GPL(at91_pmc_base); #define cpu_has_300M_plla() (cpu_is_at91sam9g10()) +#define cpu_has_240M_plla() (cpu_is_at91sam9261() \ + || cpu_is_at91sam9263() \ + || cpu_is_at91sam9rl()) + +#define cpu_has_210M_plla() (cpu_is_at91sam9260()) + #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ || cpu_is_at91sam9g45() \ || cpu_is_at91sam9x5() \ @@ -706,6 +712,12 @@ static int __init at91_pmc_init(unsigned long main_clock) } else if (cpu_has_800M_plla()) { if (plla.rate_hz > 800000000) pll_overclock = true; + } else if (cpu_has_240M_plla()) { + if (plla.rate_hz > 240000000) + pll_overclock = true; + } else if (cpu_has_210M_plla()) { + if (plla.rate_hz > 210000000) + pll_overclock = true; } else { if (plla.rate_hz > 209000000) pll_overclock = true; -- cgit v0.10.2 From 9e0255dd035348953e23161b7158b2ce0ddc182e Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Fri, 17 Aug 2012 16:23:56 +0800 Subject: ARM: at91/dts: remove partial parameter in at91sam9g25ek.dts Remove the malformed "mem=" bootargs parameter in at91sam9g25ek.dts Signed-off-by: Bo Shen Signed-off-by: Nicolas Ferre diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts index 7829a4d..96514c1 100644 --- a/arch/arm/boot/dts/at91sam9g25ek.dts +++ b/arch/arm/boot/dts/at91sam9g25ek.dts @@ -15,7 +15,7 @@ compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; chosen { - bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs"; + bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs"; }; ahb { -- cgit v0.10.2 From a0dfb2634e5671770f598cda08002d8cda66ac77 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Thu, 23 Aug 2012 19:51:21 +0800 Subject: af_packet: match_fanout_group() can be static cc: Eric Leblond Signed-off-by: Fengguang Wu Signed-off-by: David S. Miller diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index aee7196..c5c9e2a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1273,7 +1273,7 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po) spin_unlock(&f->lock); } -bool match_fanout_group(struct packet_type *ptype, struct sock * sk) +static bool match_fanout_group(struct packet_type *ptype, struct sock * sk) { if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout) return true; -- cgit v0.10.2 From 0ff9514b579b4f2f3e6038cd961ce64c224c3c73 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 23 Aug 2012 10:53:08 -0600 Subject: PCI: Don't print anything while decoding is disabled If we try to print to the console device while its decoding is disabled, the system will hang. Reported-and-tested-by: Olof Johansson Signed-off-by: Bjorn Helgaas Acked-by: Olof Johansson diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6c143b4..9f8a6b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -144,15 +144,13 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar) case PCI_BASE_ADDRESS_MEM_TYPE_32: break; case PCI_BASE_ADDRESS_MEM_TYPE_1M: - dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n"); + /* 1M mem BAR treated as 32-bit BAR */ break; case PCI_BASE_ADDRESS_MEM_TYPE_64: flags |= IORESOURCE_MEM_64; break; default: - dev_warn(&dev->dev, - "mem unknown type %x treated as 32-bit BAR\n", - mem_type); + /* mem unknown type treated as 32-bit BAR */ break; } return flags; @@ -173,9 +171,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, u32 l, sz, mask; u16 orig_cmd; struct pci_bus_region region; + bool bar_too_big = false, bar_disabled = false; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; + /* No printks while decoding is disabled! */ if (!dev->mmio_always_on) { pci_read_config_word(dev, PCI_COMMAND, &orig_cmd); pci_write_config_word(dev, PCI_COMMAND, @@ -240,8 +240,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, goto fail; if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { - dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", - pos); + bar_too_big = true; goto fail; } @@ -252,12 +251,11 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, region.start = 0; region.end = sz64; pcibios_bus_to_resource(dev, res, ®ion); + bar_disabled = true; } else { region.start = l64; region.end = l64 + sz64; pcibios_bus_to_resource(dev, res, ®ion); - dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", - pos, res); } } else { sz = pci_size(l, sz, mask); @@ -268,18 +266,23 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, region.start = l; region.end = l + sz; pcibios_bus_to_resource(dev, res, ®ion); - - dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); } - out: + goto out; + + +fail: + res->flags = 0; +out: if (!dev->mmio_always_on) pci_write_config_word(dev, PCI_COMMAND, orig_cmd); + if (bar_too_big) + dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos); + if (res->flags && !bar_disabled) + dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); + return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; - fail: - res->flags = 0; - goto out; } static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) -- cgit v0.10.2 From ac70b2e9a13423b5efa0178e081936ce6979aea5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 15 Aug 2012 18:09:15 +0100 Subject: sfc: Fix reporting of IPv4 full filters through ethtool ETHTOOL_GRXCLSRULE returns filters for a TCP/IPv4 or UDP/IPv4 4-tuple with source and destination swapped. Signed-off-by: Ben Hutchings diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 8cba2df..5faedd8 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -863,8 +863,8 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, &ip_entry->ip4dst, &ip_entry->pdst); if (rc != 0) { rc = efx_filter_get_ipv4_full( - &spec, &proto, &ip_entry->ip4src, &ip_entry->psrc, - &ip_entry->ip4dst, &ip_entry->pdst); + &spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst, + &ip_entry->ip4src, &ip_entry->psrc); EFX_WARN_ON_PARANOID(rc); ip_mask->ip4src = ~0; ip_mask->psrc = ~0; -- cgit v0.10.2 From ef813c412c0cf254ddce7d922289e2d6a69960f0 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Wed, 8 Aug 2012 19:15:01 +0400 Subject: can: softing: Fix potential memory leak in softing_load_fw() Do not leak memory by updating pointer with potentially NULL realloc return value. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Marc Kleine-Budde diff --git a/drivers/net/can/softing/softing_fw.c b/drivers/net/can/softing/softing_fw.c index 3105961..b595d34 100644 --- a/drivers/net/can/softing/softing_fw.c +++ b/drivers/net/can/softing/softing_fw.c @@ -150,7 +150,7 @@ int softing_load_fw(const char *file, struct softing *card, const uint8_t *mem, *end, *dat; uint16_t type, len; uint32_t addr; - uint8_t *buf = NULL; + uint8_t *buf = NULL, *new_buf; int buflen = 0; int8_t type_end = 0; @@ -199,11 +199,12 @@ int softing_load_fw(const char *file, struct softing *card, if (len > buflen) { /* align buflen */ buflen = (len + (1024-1)) & ~(1024-1); - buf = krealloc(buf, buflen, GFP_KERNEL); - if (!buf) { + new_buf = krealloc(buf, buflen, GFP_KERNEL); + if (!new_buf) { ret = -ENOMEM; goto failed; } + buf = new_buf; } /* verify record data */ memcpy_fromio(buf, &dpram[addr + offset], len); -- cgit v0.10.2 From da3d50ef308d53f216f1f92f4971f245c13e9f65 Mon Sep 17 00:00:00 2001 From: Sven Schmitt Date: Thu, 9 Aug 2012 14:46:34 +0200 Subject: can: sja1000_platform: fix wrong flag IRQF_SHARED for interrupt sharing The sja1000 platform driver wrongly assumes that a shared IRQ is indicated with the IRQF_SHARED flag in irq resource flags. This patch changes the driver to handle the correct flag IORESOURCE_IRQ_SHAREABLE instead. There are no mainline users of the platform driver which wrongly make use of IRQF_SHARED. Signed-off-by: Sven Schmitt Acked-by: Yegor Yefremov Signed-off-by: Marc Kleine-Budde diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 4f50145..662c5f7 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -109,7 +109,9 @@ static int sp_probe(struct platform_device *pdev) priv = netdev_priv(dev); dev->irq = res_irq->start; - priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED); + priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) + priv->irq_flags |= IRQF_SHARED; priv->reg_base = addr; /* The CAN clock frequency is half the oscillator clock frequency */ priv->can.clock.freq = pdata->osc_freq / 2; -- cgit v0.10.2 From 78df76a065ae3b5dbcb9a29912adc02f697de498 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 24 Aug 2012 05:40:47 +0000 Subject: ipv4: take rt_uncached_lock only if needed Multicast traffic allocates dst with DST_NOCACHE, but dst is not inserted into rt_uncached_list. This slowdown multicast workloads on SMP because rt_uncached_lock is contended. Change the test before taking the lock to actually check the dst was inserted into rt_uncached_list. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8c8c748..24fd4c5 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1263,7 +1263,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst) { struct rtable *rt = (struct rtable *) dst; - if (dst->flags & DST_NOCACHE) { + if (!list_empty(&rt->rt_uncached)) { spin_lock_bh(&rt_uncached_lock); list_del(&rt->rt_uncached); spin_unlock_bh(&rt_uncached_lock); -- cgit v0.10.2 From bd4242dfe85470b9caecbd049310518f9b9e3f14 Mon Sep 17 00:00:00 2001 From: Rayagond Kokatanur Date: Wed, 22 Aug 2012 21:28:18 +0000 Subject: stmmac: add header inclusion protection This patch adds "#ifndef __
_H" for protecting header from double inclusion. Signed-off-by: Rayagond Kokatanur Hacked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index e2d0832..719be39 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -22,6 +22,9 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __COMMON_H__ +#define __COMMON_H__ + #include #include #include @@ -366,3 +369,5 @@ extern void stmmac_set_mac(void __iomem *ioaddr, bool enable); extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr); extern const struct stmmac_ring_mode_ops ring_mode_ops; + +#endif /* __COMMON_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h index 9820ec8..223adf9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/descs.h +++ b/drivers/net/ethernet/stmicro/stmmac/descs.h @@ -20,6 +20,10 @@ Author: Giuseppe Cavallaro *******************************************************************************/ + +#ifndef __DESCS_H__ +#define __DESCS_H__ + struct dma_desc { /* Receive descriptor */ union { @@ -166,3 +170,5 @@ enum tdes_csum_insertion { * is not calculated */ cic_full = 3, /* IP header and pseudoheader */ }; + +#endif /* __DESCS_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h index dd8d6e1..7ee9499 100644 --- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h +++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h @@ -27,6 +27,9 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __DESC_COM_H__ +#define __DESC_COM_H__ + #if defined(CONFIG_STMMAC_RING) static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end) { @@ -124,3 +127,5 @@ static inline void norm_set_tx_desc_len(struct dma_desc *p, int len) p->des01.tx.buffer1_size = len; } #endif + +#endif /* __DESC_COM_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100.h b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h index 7c6d857..2ec6aea 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100.h @@ -22,6 +22,9 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __DWMAC100_H__ +#define __DWMAC100_H__ + #include #include "common.h" @@ -119,3 +122,5 @@ enum ttc_control { #define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */ extern const struct stmmac_dma_ops dwmac100_dma_ops; + +#endif /* __DWMAC100_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index b4c44a5..0e4cace 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -19,6 +19,8 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __DWMAC1000_H__ +#define __DWMAC1000_H__ #include #include "common.h" @@ -232,3 +234,4 @@ enum rtc_control { #define DWMAC_CORE_3_40 0x34 extern const struct stmmac_dma_ops dwmac1000_dma_ops; +#endif /* __DWMAC1000_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h index e678ce3..e49c9a0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h @@ -22,6 +22,9 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __DWMAC_DMA_H__ +#define __DWMAC_DMA_H__ + /* DMA CRS Control and Status Register Mapping */ #define DMA_BUS_MODE 0x00001000 /* Bus Mode */ #define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */ @@ -109,3 +112,5 @@ extern void dwmac_dma_start_rx(void __iomem *ioaddr); extern void dwmac_dma_stop_rx(void __iomem *ioaddr); extern int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x); + +#endif /* __DWMAC_DMA_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h index a3835202..67995ef 100644 --- a/drivers/net/ethernet/stmicro/stmmac/mmc.h +++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h @@ -22,6 +22,9 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __MMC_H__ +#define __MMC_H__ + /* MMC control register */ /* When set, all counter are reset */ #define MMC_CNTRL_COUNTER_RESET 0x1 @@ -129,3 +132,5 @@ struct stmmac_counters { extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode); extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr); extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc); + +#endif /* __MMC_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index f2d3665..e872e1d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -20,6 +20,9 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __STMMAC_H__ +#define __STMMAC_H__ + #define STMMAC_RESOURCE_NAME "stmmaceth" #define DRV_MODULE_VERSION "March_2012" @@ -166,3 +169,5 @@ static inline void stmmac_unregister_pci(void) { } #endif /* CONFIG_STMMAC_PCI */ + +#endif /* __STMMAC_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h index 6863590..aea9b14 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_timer.h @@ -21,6 +21,8 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#ifndef __STMMAC_TIMER_H__ +#define __STMMAC_TIMER_H__ struct stmmac_timer { void (*timer_start) (unsigned int new_freq); @@ -40,3 +42,5 @@ void stmmac_schedule(struct net_device *dev); extern int tmu2_register_user(void *fnt, void *data); extern void tmu2_unregister_user(void); #endif + +#endif /* __STMMAC_TIMER_H__ */ -- cgit v0.10.2 From 20e1db19db5d6b9e4e83021595eab0dc8f107bef Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 23 Aug 2012 02:09:11 +0000 Subject: netlink: fix possible spoofing from non-root processes Non-root user-space processes can send Netlink messages to other processes that are well-known for being subscribed to Netlink asynchronous notifications. This allows ilegitimate non-root process to send forged messages to Netlink subscribers. The userspace process usually verifies the legitimate origin in two ways: a) Socket credentials. If UID != 0, then the message comes from some ilegitimate process and the message needs to be dropped. b) Netlink portID. In general, portID == 0 means that the origin of the messages comes from the kernel. Thus, discarding any message not coming from the kernel. However, ctnetlink sets the portID in event messages that has been triggered by some user-space process, eg. conntrack utility. So other processes subscribed to ctnetlink events, eg. conntrackd, know that the event was triggered by some user-space action. Neither of the two ways to discard ilegitimate messages coming from non-root processes can help for ctnetlink. This patch adds capability validation in case that dst_pid is set in netlink_sendmsg(). This approach is aggressive since existing applications using any Netlink bus to deliver messages between two user-space processes will break. Note that the exception is NETLINK_USERSOCK, since it is reserved for netlink-to-netlink userspace communication. Still, if anyone wants that his Netlink bus allows netlink-to-netlink userspace, then they can set NL_NONROOT_SEND. However, by default, I don't think it makes sense to allow to use NETLINK_ROUTE to communicate two processes that are sending no matter what information that is not related to link/neighbouring/routing. They should be using NETLINK_USERSOCK instead for that. Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1445d73..5270238 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1373,7 +1373,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, dst_pid = addr->nl_pid; dst_group = ffs(addr->nl_groups); err = -EPERM; - if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND)) + if ((dst_group || dst_pid) && + !netlink_capable(sock, NL_NONROOT_SEND)) goto out; } else { dst_pid = nlk->dst_pid; @@ -2147,6 +2148,7 @@ static void __init netlink_add_usersock_entry(void) rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners); nl_table[NETLINK_USERSOCK].module = THIS_MODULE; nl_table[NETLINK_USERSOCK].registered = 1; + nl_table[NETLINK_USERSOCK].nl_nonroot = NL_NONROOT_SEND; netlink_table_ungrab(); } -- cgit v0.10.2 From 7c4a56fec379ac0d7754e0d4da6a7361f1a4fe64 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 23 Aug 2012 07:05:17 +0000 Subject: tcp: fix cwnd reduction for non-sack recovery The cwnd reduction in fast recovery is based on the number of packets newly delivered per ACK. For non-sack connections every DUPACK signifies a packet has been delivered, but the sender mistakenly skips counting them for cwnd reduction. The fix is to compute newly_acked_sacked after DUPACKs are accounted in sacked_out for non-sack connections. Signed-off-by: Yuchung Cheng Acked-by: Nandita Dukkipati Acked-by: Neal Cardwell Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 85308b9..6e38c6c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2926,13 +2926,14 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack) * tcp_xmit_retransmit_queue(). */ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, - int newly_acked_sacked, bool is_dupack, + int prior_sacked, bool is_dupack, int flag) { struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && (tcp_fackets_out(tp) > tp->reordering)); + int newly_acked_sacked = 0; int fast_rexmit = 0; if (WARN_ON(!tp->packets_out && tp->sacked_out)) @@ -2992,6 +2993,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, tcp_add_reno_sack(sk); } else do_lost = tcp_try_undo_partial(sk, pkts_acked); + newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked; break; case TCP_CA_Loss: if (flag & FLAG_DATA_ACKED) @@ -3013,6 +3015,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, if (is_dupack) tcp_add_reno_sack(sk); } + newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked; if (icsk->icsk_ca_state <= TCP_CA_Disorder) tcp_try_undo_dsack(sk); @@ -3590,7 +3593,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) int prior_packets; int prior_sacked = tp->sacked_out; int pkts_acked = 0; - int newly_acked_sacked = 0; bool frto_cwnd = false; /* If the ack is older than previous acks @@ -3666,8 +3668,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una); pkts_acked = prior_packets - tp->packets_out; - newly_acked_sacked = (prior_packets - prior_sacked) - - (tp->packets_out - tp->sacked_out); if (tp->frto_counter) frto_cwnd = tcp_process_frto(sk, flag); @@ -3681,7 +3681,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) tcp_may_raise_cwnd(sk, flag)) tcp_cong_avoid(sk, ack, prior_in_flight); is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); - tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, + tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, is_dupack, flag); } else { if ((flag & FLAG_DATA_ACKED) && !frto_cwnd) @@ -3698,7 +3698,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) no_queue: /* If data was DSACKed, see if we can undo a cwnd reduction. */ if (flag & FLAG_DSACKING_ACK) - tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, + tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, is_dupack, flag); /* If this ack opens up a zero window, clear backoff. It was * being used to time the probes, and is probably far higher than @@ -3718,8 +3718,7 @@ old_ack: */ if (TCP_SKB_CB(skb)->sacked) { flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una); - newly_acked_sacked = tp->sacked_out - prior_sacked; - tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked, + tcp_fastretrans_alert(sk, pkts_acked, prior_sacked, is_dupack, flag); } -- cgit v0.10.2 From 5dd18b0150e6f4eb3a9d06a2621cad8c73a3eccf Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Tue, 7 Aug 2012 12:48:21 +0530 Subject: arm/dts: omap5: Add mmc controller nodes and board data Add OMAP MMC related device tree data for OMAP5. Signed-off-by: Balaji T K Acked-by: Arnd Bergmann Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap5-evm.dts b/arch/arm/boot/dts/omap5-evm.dts index 200c39a..7bb0c9d 100644 --- a/arch/arm/boot/dts/omap5-evm.dts +++ b/arch/arm/boot/dts/omap5-evm.dts @@ -17,4 +17,35 @@ device_type = "memory"; reg = <0x80000000 0x40000000>; /* 1 GB */ }; + + vmmcsd_fixed: fixedregulator-mmcsd { + compatible = "regulator-fixed"; + regulator-name = "vmmcsd_fixed"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; +}; + +&mmc1 { + vmmc-supply = <&vmmcsd_fixed>; + bus-width = <4>; +}; + +&mmc2 { + vmmc-supply = <&vmmcsd_fixed>; + bus-width = <8>; + ti,non-removable; +}; + +&mmc3 { + bus-width = <4>; + ti,non-removable; +}; + +&mmc4 { + status = "disabled"; +}; + +&mmc5 { + status = "disabled"; }; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 57e5270..881d60c 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -180,5 +180,36 @@ ti,hwmods = "uart6"; clock-frequency = <48000000>; }; + + mmc1: mmc@4809c000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc1"; + ti,dual-volt; + ti,needs-special-reset; + }; + + mmc2: mmc@480b4000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc2"; + ti,needs-special-reset; + }; + + mmc3: mmc@480ad000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc3"; + ti,needs-special-reset; + }; + + mmc4: mmc@480d1000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc4"; + ti,needs-special-reset; + }; + + mmc5: mmc@480d5000 { + compatible = "ti,omap4-hsmmc"; + ti,hwmods = "mmc5"; + ti,needs-special-reset; + }; }; }; -- cgit v0.10.2 From 53d91034cf29936cabf9a4d59270dc94ed7e6c1d Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Wed, 15 Aug 2012 16:53:25 +0530 Subject: arm/dts: AM33XX: Set the default status of module to "disabled" state Ideally in common SoC dtsi file should set all modules to "disabled" state and it should get enabled in respective EVM/Board dts file as per usage. This patch sets default status of all modules to "disabled" state in am33xx.dtsi file. Currently there are no modules supported as part of Bone and EVM dts support, so care to add entry "status = "okay"" while adding support for any module. Signed-off-by: Vaibhav Hiremath Acked-by: Arnd Bergmann Cc: Benoit Cousson Cc: Grant Likely Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts index a9af4db..a7906cb 100644 --- a/arch/arm/boot/dts/am335x-bone.dts +++ b/arch/arm/boot/dts/am335x-bone.dts @@ -17,4 +17,10 @@ device_type = "memory"; reg = <0x80000000 0x10000000>; /* 256 MB */ }; + + ocp { + uart1: serial@44E09000 { + status = "okay"; + }; + }; }; diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index d6a97d9..5dd8a6b 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -17,4 +17,10 @@ device_type = "memory"; reg = <0x80000000 0x10000000>; /* 256 MB */ }; + + ocp { + uart1: serial@44E09000 { + status = "okay"; + }; + }; }; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 59509c4..5f6c8e3 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -102,36 +102,42 @@ compatible = "ti,omap3-uart"; ti,hwmods = "uart1"; clock-frequency = <48000000>; + status = "disabled"; }; uart2: serial@48022000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart2"; clock-frequency = <48000000>; + status = "disabled"; }; uart3: serial@48024000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart3"; clock-frequency = <48000000>; + status = "disabled"; }; uart4: serial@481A6000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart4"; clock-frequency = <48000000>; + status = "disabled"; }; uart5: serial@481A8000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart5"; clock-frequency = <48000000>; + status = "disabled"; }; uart6: serial@481AA000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart6"; clock-frequency = <48000000>; + status = "disabled"; }; i2c1: i2c@44E0B000 { @@ -139,6 +145,7 @@ #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c1"; + status = "disabled"; }; i2c2: i2c@4802A000 { @@ -146,6 +153,7 @@ #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c2"; + status = "disabled"; }; i2c3: i2c@4819C000 { @@ -153,6 +161,7 @@ #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c3"; + status = "disabled"; }; }; }; -- cgit v0.10.2 From 85d7ff9b907685b6469058888f1d961b3e8d47ad Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 23 Aug 2012 09:51:29 -0700 Subject: ARM: omap: add dtb targets Makes it easier to just do 'make dtbs' for whatever the kernel was configured for, just like some other platforms. Signed-off-by: Olof Johansson Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot index b03e562..6cf1c2d 100644 --- a/arch/arm/mach-omap2/Makefile.boot +++ b/arch/arm/mach-omap2/Makefile.boot @@ -1,3 +1,9 @@ zreladdr-y += 0x80008000 params_phys-y := 0x80000100 initrd_phys-y := 0x80800000 + +dtb-$(CONFIG_SOC_OMAP2420) += omap2420-h4.dtb +dtb-$(CONFIG_ARCH_OMAP3) += omap3-beagle.dtb omap3-evm.dtb +dtb-$(CONFIG_ARCH_OMAP4) += omap4-panda.dtb omap4-pandaES.dtb +dtb-$(CONFIG_ARCH_OMAP4) += omap4-var_som.dtb omap4-sdp.dtb +dtb-$(CONFIG_SOC_OMAP5) += omap5-evm.dtb -- cgit v0.10.2 From 2d85b9494d10501f20ebf043f8d599e45736d78f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 24 Jul 2012 15:26:08 +0200 Subject: ARM: mach-shmobile: armadillo800eva: Fix GPIO buttons descriptions The GPIO buttons are named SW3, SW4, SW5 and SW6 on the board silkscreen. Update the buttons descriptions accordingly. Signed-off-by: Laurent Pinchart Acked-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index cf10f92..a002504 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -523,10 +523,10 @@ static struct platform_device hdmi_lcdc_device = { #define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } static struct gpio_keys_button gpio_buttons[] = { - GPIO_KEY(KEY_POWER, GPIO_PORT99, "SW1"), - GPIO_KEY(KEY_BACK, GPIO_PORT100, "SW2"), - GPIO_KEY(KEY_MENU, GPIO_PORT97, "SW3"), - GPIO_KEY(KEY_HOME, GPIO_PORT98, "SW4"), + GPIO_KEY(KEY_POWER, GPIO_PORT99, "SW3"), + GPIO_KEY(KEY_BACK, GPIO_PORT100, "SW4"), + GPIO_KEY(KEY_MENU, GPIO_PORT97, "SW5"), + GPIO_KEY(KEY_HOME, GPIO_PORT98, "SW6"), }; static struct gpio_keys_platform_data gpio_key_info = { -- cgit v0.10.2 From 5c1d2d16772e2d7d4e2e8da99a92d6f50b9102f0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 24 Jul 2012 15:26:09 +0200 Subject: ARM: mach-shmobile: armadillo800eva: Enable power button as wakeup source Signed-off-by: Laurent Pinchart Acked-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index a002504..65cb793 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -520,10 +520,11 @@ static struct platform_device hdmi_lcdc_device = { }; /* GPIO KEY */ -#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 } +#define GPIO_KEY(c, g, d, ...) \ + { .code = c, .gpio = g, .desc = d, .active_low = 1, __VA_ARGS__ } static struct gpio_keys_button gpio_buttons[] = { - GPIO_KEY(KEY_POWER, GPIO_PORT99, "SW3"), + GPIO_KEY(KEY_POWER, GPIO_PORT99, "SW3", .wakeup = 1), GPIO_KEY(KEY_BACK, GPIO_PORT100, "SW4"), GPIO_KEY(KEY_MENU, GPIO_PORT97, "SW5"), GPIO_KEY(KEY_HOME, GPIO_PORT98, "SW6"), -- cgit v0.10.2 From 51a6149b89b822cacf572b2ca2a15cb6f2232b11 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 23 Aug 2012 15:05:07 +0200 Subject: ARM: at91/feature-removal-schedule: delay at91_mci removal Delay sd/mmc driver at91_mci.c removal because of tight schedule to move platform data to new driver atmel-mci. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index afaff31..f4d8c71 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -579,7 +579,7 @@ Why: KVM tracepoints provide mostly equivalent information in a much more ---------------------------- What: at91-mci driver ("CONFIG_MMC_AT91") -When: 3.7 +When: 3.8 Why: There are two mci drivers: at91-mci and atmel-mci. The PDC support was added to atmel-mci as a first step to support more chips. Then at91-mci was kept only for old IP versions (on at91rm9200 and -- cgit v0.10.2 From 67ddbb3e6568fb1820b2cc45b00c50702b114801 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 23 Aug 2012 10:51:55 -0400 Subject: HID: add NOGET quirk for Eaton Ellipse MAX UPS This patch (as1603) adds a NOGET quirk for the Eaton Ellipse MAX UPS device. (The USB IDs were already present in hid-ids.h, apparently under a different name.) Signed-off-by: Alan Stern Reported-by: Laurent Bigonville CC: Signed-off-by: Jiri Kosina diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 903eef3..991e85c 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -70,6 +70,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v0.10.2 From 983f6b93818aa62fbc74c37fcb8a482718a19252 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Aug 2012 09:18:01 -0700 Subject: ALSA: hda - Avoid unnecessary parameter read for EPSS EPSS parameter should be static, so we can read it once and remember. This also allows more easily to override the wrong EPSS capability reported from a codec by changing the flag in the codec initialization step. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f560051..f25c24c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1209,6 +1209,9 @@ static void snd_hda_codec_free(struct hda_codec *codec) kfree(codec); } +static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, + hda_nid_t fg, unsigned int power_state); + static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state); @@ -1317,6 +1320,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, AC_VERB_GET_SUBSYSTEM_ID, 0); } + codec->epss = snd_hda_codec_get_supported_ps(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_EPSS); + /* power-up all before initialization */ hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, @@ -3543,8 +3550,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, /* this delay seems necessary to avoid click noise at power-down */ if (power_state == AC_PWRST_D3) { /* transition time less than 10ms for power down */ - bool epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); - msleep(epss ? 10 : 100); + msleep(codec->epss ? 10 : 100); } /* repeat power states setting at most 10 times*/ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 7fbc1bc..e5a7e19 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -862,6 +862,7 @@ struct hda_codec { unsigned int ignore_misc_bit:1; /* ignore MISC_NO_PRESENCE bit */ unsigned int no_jack_detect:1; /* Machine has no jack-detection */ unsigned int pcm_format_first:1; /* PCM format must be set first */ + unsigned int epss:1; /* supporting EPSS? */ #ifdef CONFIG_SND_HDA_POWER_SAVE unsigned int power_on :1; /* current (global) power-state */ int power_transition; /* power-state in transition */ -- cgit v0.10.2 From c36b5b054aaf14d68261970e3769398110e636d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Aug 2012 09:20:13 -0700 Subject: ALSA: hda - Don't trust codec EPSS bit for IDT 92HD83xx & co These codecs seem reporting EPSS but require longer delay for the proper D3 transition. For example, D3_STOP_CLOCK_OK bit won't be set correctly even after D3. In this patch, codec->epss flag is overridden for avoid the misbehavior. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3edd73c..6f806d3 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5534,6 +5534,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); } + codec->epss = 0; /* longer delay needed for D3 */ codec->no_trigger_sense = 1; codec->spec = spec; -- cgit v0.10.2 From 7ce9bf1f4785dab0598a19a7fcb0733a18193e4e Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 27 Aug 2012 20:27:19 +0200 Subject: mm: cma: fix alignment requirements for contiguous regions Contiguous Memory Allocator requires each of its regions to be aligned in such a way that it is possible to change migration type for all pageblocks holding it and then isolate page of largest possible order from the buddy allocator (which is MAX_ORDER-1). This patch relaxes alignment requirements by one order, because MAX_ORDER alignment is not really needed. Signed-off-by: Marek Szyprowski CC: Michal Nazarewicz Acked-by: Michal Nazarewicz diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 78efb03..34d94c7 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -250,7 +250,7 @@ int __init dma_declare_contiguous(struct device *dev, unsigned long size, return -EINVAL; /* Sanitise input arguments */ - alignment = PAGE_SIZE << max(MAX_ORDER, pageblock_order); + alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); base = ALIGN(base, alignment); size = ALIGN(size, alignment); limit &= ~(alignment - 1); -- cgit v0.10.2 From e092705bcd53de3bafc3053b0b55bf83e5d6711f Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 20 Aug 2012 14:39:39 +0200 Subject: ARM: relax conditions required for enabling Contiguous Memory Allocator Contiguous Memory Allocator requires only paging and MMU enabled not particular CPU architectures, so there is no need for strict dependency on CPU type. This enables to use CMA on some older ARM v5 systems which also might need large contiguous blocks for the multimedia processing hw modules. Reported-by: Prabhakar Lad Signed-off-by: Marek Szyprowski Tested-by: Prabhakar Lad diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6d6e18f..0824a91 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -6,7 +6,7 @@ config ARM select HAVE_DMA_API_DEBUG select HAVE_IDE if PCI || ISA || PCMCIA select HAVE_DMA_ATTRS - select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7) + select HAVE_DMA_CONTIGUOUS if MMU select HAVE_MEMBLOCK select RTC_LIB select SYS_SUPPORTS_APM_EMULATION -- cgit v0.10.2 From 6e5267aa543817015edb4a65c66e15f9809f92bd Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 20 Aug 2012 11:19:25 +0200 Subject: ARM: DMA-Mapping: add function for setting coherent pool size from platform code Some platforms might require to increase atomic coherent pool to make sure that their device will be able to allocate all their buffers from atomic context. This function can be also used to decrease atomic coherent pool size if coherent allocations are not used for the given sub-platform. Suggested-by: Josh Coombs Signed-off-by: Marek Szyprowski diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 2ae842d..5c44dcb 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -203,6 +203,13 @@ static inline void dma_free_writecombine(struct device *dev, size_t size, } /* + * This can be called during early boot to increase the size of the atomic + * coherent DMA pool above the default value of 256KiB. It must be called + * before postcore_initcall. + */ +extern void __init init_dma_coherent_pool_size(unsigned long size); + +/* * This can be called during boot to increase the size of the consistent * DMA region above it's default value of 2MB. It must be called before the * memory allocator is initialised, i.e. before any core_initcall. diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 4e7d118..d1cc9c1 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -267,6 +267,8 @@ static void __dma_free_remap(void *cpu_addr, size_t size) vunmap(cpu_addr); } +#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K + struct dma_pool { size_t size; spinlock_t lock; @@ -277,7 +279,7 @@ struct dma_pool { }; static struct dma_pool atomic_pool = { - .size = SZ_256K, + .size = DEFAULT_DMA_COHERENT_POOL_SIZE, }; static int __init early_coherent_pool(char *p) @@ -287,6 +289,21 @@ static int __init early_coherent_pool(char *p) } early_param("coherent_pool", early_coherent_pool); +void __init init_dma_coherent_pool_size(unsigned long size) +{ + /* + * Catch any attempt to set the pool size too late. + */ + BUG_ON(atomic_pool.vaddr); + + /* + * Set architecture specific coherent pool size only if + * it has not been changed by kernel command line parameter. + */ + if (atomic_pool.size == DEFAULT_DMA_COHERENT_POOL_SIZE) + atomic_pool.size = size; +} + /* * Initialise the coherent pool for atomic allocations. */ -- cgit v0.10.2 From fb71285f0c1633a85544784aae7577502274b77a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 22 Aug 2012 14:50:42 +0200 Subject: ARM: DMA-Mapping: print warning when atomic coherent allocation fails Print a loud warning when system runs out of memory from atomic DMA coherent pool to let users notice the potential problem. Reported-by: Aaro Koskinen Signed-off-by: Marek Szyprowski diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index d1cc9c1..acced93 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -461,6 +461,10 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) bitmap_set(pool->bitmap, pageno, count); ptr = pool->vaddr + PAGE_SIZE * pageno; *ret_page = pool->page + pageno; + } else { + pr_err_once("ERROR: %u KiB atomic DMA coherent pool is too small!\n" + "Please increase it with coherent_pool= kernel parameter!\n", + (unsigned)pool->size / 1024); } spin_unlock_irqrestore(&pool->lock, flags); -- cgit v0.10.2 From cb01b633eeb77ae7128cab0a3b5d3de56da6e913 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 28 Aug 2012 20:57:41 +0200 Subject: ARM: Kirkwood: increase atomic coherent pool size The default 256 KiB coherent pool may be too small for some of the Kirkwood devices, so increase it to make sure that devices will be able to allocate their buffers with GFP_ATOMIC flag. Suggested-by: Josh Coombs Signed-off-by: Marek Szyprowski Acked-by: Jason Cooper diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index c4b64ad..d748f50 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -517,6 +517,13 @@ void __init kirkwood_wdt_init(void) void __init kirkwood_init_early(void) { orion_time_set_base(TIMER_VIRT_BASE); + + /* + * Some Kirkwood devices allocate their coherent buffers from atomic + * context. Increase size of atomic coherent pool to make sure such + * the allocations won't fail. + */ + init_dma_coherent_pool_size(SZ_1M); } int kirkwood_tclk; -- cgit v0.10.2 From 6b3fe47264262fa082897ebe8ae01041eae65e14 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 28 Aug 2012 08:13:01 +0300 Subject: ARM: dma-mapping: atomic_pool with struct page **pages struct page **pages is necessary to align with non atomic path in __iommu_get_pages(). atomic_pool() has the intialized **pages instead of just *page. Signed-off-by: Hiroshi Doyu Signed-off-by: Marek Szyprowski diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index acced93..9a21284 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -275,7 +275,7 @@ struct dma_pool { unsigned long *bitmap; unsigned long nr_pages; void *vaddr; - struct page *page; + struct page **pages; }; static struct dma_pool atomic_pool = { @@ -314,6 +314,7 @@ static int __init atomic_pool_init(void) unsigned long nr_pages = pool->size >> PAGE_SHIFT; unsigned long *bitmap; struct page *page; + struct page **pages; void *ptr; int bitmap_size = BITS_TO_LONGS(nr_pages) * sizeof(long); @@ -321,21 +322,31 @@ static int __init atomic_pool_init(void) if (!bitmap) goto no_bitmap; + pages = kzalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); + if (!pages) + goto no_pages; + if (IS_ENABLED(CONFIG_CMA)) ptr = __alloc_from_contiguous(NULL, pool->size, prot, &page); else ptr = __alloc_remap_buffer(NULL, pool->size, GFP_KERNEL, prot, &page, NULL); if (ptr) { + int i; + + for (i = 0; i < nr_pages; i++) + pages[i] = page + i; + spin_lock_init(&pool->lock); pool->vaddr = ptr; - pool->page = page; + pool->pages = pages; pool->bitmap = bitmap; pool->nr_pages = nr_pages; pr_info("DMA: preallocated %u KiB pool for atomic coherent allocations\n", (unsigned)pool->size / 1024); return 0; } +no_pages: kfree(bitmap); no_bitmap: pr_err("DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", @@ -460,7 +471,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) if (pageno < pool->nr_pages) { bitmap_set(pool->bitmap, pageno, count); ptr = pool->vaddr + PAGE_SIZE * pageno; - *ret_page = pool->page + pageno; + *ret_page = pool->pages[pageno]; } else { pr_err_once("ERROR: %u KiB atomic DMA coherent pool is too small!\n" "Please increase it with coherent_pool= kernel parameter!\n", -- cgit v0.10.2 From 21d0a75951ccf71f671eb24b61a8ad2b497be4b4 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 28 Aug 2012 08:13:02 +0300 Subject: ARM: dma-mapping: Refactor out to introduce __in_atomic_pool Check the given range("start", "size") is included in "atomic_pool" or not. Signed-off-by: Hiroshi Doyu Signed-off-by: Marek Szyprowski diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 9a21284..882eacc6 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -482,20 +482,34 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page) return ptr; } +static bool __in_atomic_pool(void *start, size_t size) +{ + struct dma_pool *pool = &atomic_pool; + void *end = start + size; + void *pool_start = pool->vaddr; + void *pool_end = pool->vaddr + pool->size; + + if (start < pool_start || start > pool_end) + return false; + + if (end <= pool_end) + return true; + + WARN(1, "Wrong coherent size(%p-%p) from atomic pool(%p-%p)\n", + start, end - 1, pool_start, pool_end - 1); + + return false; +} + static int __free_from_pool(void *start, size_t size) { struct dma_pool *pool = &atomic_pool; unsigned long pageno, count; unsigned long flags; - if (start < pool->vaddr || start > pool->vaddr + pool->size) + if (!__in_atomic_pool(start, size)) return 0; - if (start + size > pool->vaddr + pool->size) { - WARN(1, "freeing wrong coherent size from pool\n"); - return 0; - } - pageno = (start - pool->vaddr) >> PAGE_SHIFT; count = size >> PAGE_SHIFT; -- cgit v0.10.2 From 665bad7bb911d392000fa69bc6b599c0df992504 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 28 Aug 2012 08:13:03 +0300 Subject: ARM: dma-mapping: Introduce __atomic_get_pages() for __iommu_get_pages() Support atomic allocation in __iommu_get_pages(). Signed-off-by: Hiroshi Doyu [moved __atomic_get_pages() under #ifdef CONFIG_ARM_DMA_USE_IOMMU to avoid unused fuction warning for no-IOMMU case] Signed-off-by: Marek Szyprowski diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 882eacc6..54b158d 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1136,10 +1136,22 @@ static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t si return 0; } +static struct page **__atomic_get_pages(void *addr) +{ + struct dma_pool *pool = &atomic_pool; + struct page **pages = pool->pages; + int offs = (addr - pool->vaddr) >> PAGE_SHIFT; + + return pages + offs; +} + static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) { struct vm_struct *area; + if (__in_atomic_pool(cpu_addr, PAGE_SIZE)) + return __atomic_get_pages(cpu_addr); + if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) return cpu_addr; -- cgit v0.10.2 From 479ed93a4b98eef03fd8260f7ddc00019221c450 Mon Sep 17 00:00:00 2001 From: Hiroshi Doyu Date: Tue, 28 Aug 2012 08:13:04 +0300 Subject: ARM: dma-mapping: IOMMU allocates pages from atomic_pool with GFP_ATOMIC Make use of the same atomic pool as DMA does, and skip a kernel page mapping which can involve sleep'able operations at allocating a kernel page table. Signed-off-by: Hiroshi Doyu Signed-off-by: Marek Szyprowski diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 54b158d..051204f 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1161,6 +1161,34 @@ static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs) return NULL; } +static void *__iommu_alloc_atomic(struct device *dev, size_t size, + dma_addr_t *handle) +{ + struct page *page; + void *addr; + + addr = __alloc_from_pool(size, &page); + if (!addr) + return NULL; + + *handle = __iommu_create_mapping(dev, &page, size); + if (*handle == DMA_ERROR_CODE) + goto err_mapping; + + return addr; + +err_mapping: + __free_from_pool(addr, size); + return NULL; +} + +static void __iommu_free_atomic(struct device *dev, struct page **pages, + dma_addr_t handle, size_t size) +{ + __iommu_remove_mapping(dev, handle, size); + __free_from_pool(page_address(pages[0]), size); +} + static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) { @@ -1171,6 +1199,9 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, *handle = DMA_ERROR_CODE; size = PAGE_ALIGN(size); + if (gfp & GFP_ATOMIC) + return __iommu_alloc_atomic(dev, size, handle); + pages = __iommu_alloc_buffer(dev, size, gfp); if (!pages) return NULL; @@ -1237,6 +1268,11 @@ void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, return; } + if (__in_atomic_pool(cpu_addr, size)) { + __iommu_free_atomic(dev, pages, handle, size); + return; + } + if (!dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs)) { unmap_kernel_range((unsigned long)cpu_addr, size); vunmap(cpu_addr); -- cgit v0.10.2 From 072a9c48600409d72aeb0d5b29fbb75861a06631 Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Fri, 24 Aug 2012 21:41:11 +0000 Subject: netpoll: revert 6bdb7fe3104 and fix be_poll() instead Against -net. In the patch "netpoll: re-enable irq in poll_napi()", I tried to fix the following warning: [100718.051041] ------------[ cut here ]------------ [100718.051048] WARNING: at kernel/softirq.c:159 local_bh_enable_ip+0x7d/0xb0() (Not tainted) [100718.051049] Hardware name: ProLiant BL460c G7 ... [100718.051068] Call Trace: [100718.051073] [] ? warn_slowpath_common+0x87/0xc0 [100718.051075] [] ? warn_slowpath_null+0x1a/0x20 [100718.051077] [] ? local_bh_enable_ip+0x7d/0xb0 [100718.051080] [] ? _spin_unlock_bh+0x1b/0x20 [100718.051085] [] ? be_process_mcc+0x74/0x230 [be2net] [100718.051088] [] ? be_poll_tx_mcc+0x16c/0x290 [be2net] [100718.051090] [] ? netpoll_poll_dev+0xd6/0x490 [100718.051095] [] ? bond_poll_controller+0x75/0x80 [bonding] [100718.051097] [] ? netpoll_poll_dev+0x45/0x490 [100718.051100] [] ? ksize+0x19/0x80 [100718.051102] [] ? netpoll_send_skb_on_dev+0x157/0x240 by reenabling IRQ before calling ->poll, but it seems more problems are introduced after that patch: http://ozlabs.org/~akpm/stuff/IMG_20120824_122054.jpg http://marc.info/?l=linux-netdev&m=134563282530588&w=2 So it is safe to fix be2net driver code directly. This patch reverts the offending commit and fixes be_poll() by avoid disabling BH there, this is okay because be_poll() can be called either by poll_napi() which already disables IRQ, or by net_rx_action() which already disables BH. Reported-by: Andrew Morton Reported-by: Sylvain Munaut Cc: Sylvain Munaut Cc: Andrew Morton Cc: David Miller Cc: Sathya Perla Cc: Subbu Seetharaman Cc: Ajit Khaparde Signed-off-by: Cong Wang Tested-by: Sylvain Munaut Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 7fac97b..8c63d06 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -259,7 +259,7 @@ int be_process_mcc(struct be_adapter *adapter) int num = 0, status = 0; struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; - spin_lock_bh(&adapter->mcc_cq_lock); + spin_lock(&adapter->mcc_cq_lock); while ((compl = be_mcc_compl_get(adapter))) { if (compl->flags & CQE_FLAGS_ASYNC_MASK) { /* Interpret flags as an async trailer */ @@ -280,7 +280,7 @@ int be_process_mcc(struct be_adapter *adapter) if (num) be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num); - spin_unlock_bh(&adapter->mcc_cq_lock); + spin_unlock(&adapter->mcc_cq_lock); return status; } @@ -295,7 +295,9 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) if (be_error(adapter)) return -EIO; + local_bh_disable(); status = be_process_mcc(adapter); + local_bh_enable(); if (atomic_read(&mcc_obj->q.used) == 0) break; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 90a903d8..78b8aa8 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3763,7 +3763,9 @@ static void be_worker(struct work_struct *work) /* when interrupts are not yet enabled, just reap any pending * mcc completions */ if (!netif_running(adapter->netdev)) { + local_bh_disable(); be_process_mcc(adapter); + local_bh_enable(); goto reschedule; } diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 346b1eb..e4ba3e7 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -168,24 +168,16 @@ static void poll_napi(struct net_device *dev) struct napi_struct *napi; int budget = 16; - WARN_ON_ONCE(!irqs_disabled()); - list_for_each_entry(napi, &dev->napi_list, dev_list) { - local_irq_enable(); if (napi->poll_owner != smp_processor_id() && spin_trylock(&napi->poll_lock)) { - rcu_read_lock_bh(); budget = poll_one_napi(rcu_dereference_bh(dev->npinfo), napi, budget); - rcu_read_unlock_bh(); spin_unlock(&napi->poll_lock); - if (!budget) { - local_irq_disable(); + if (!budget) break; - } } - local_irq_disable(); } } -- cgit v0.10.2 From 0a54e939d8c2647c711ef2369c3e73c3b7f3028c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 29 Aug 2012 06:49:11 +0000 Subject: ipvs: fix error return code Initialize return variable before exiting on an error path. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Acked-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 72bf32a..f51013c 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1171,8 +1171,10 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u, goto out_err; } svc->stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats); - if (!svc->stats.cpustats) + if (!svc->stats.cpustats) { + ret = -ENOMEM; goto out_err; + } /* I'm the first user of the service */ atomic_set(&svc->usecnt, 0); -- cgit v0.10.2 From ef6acf68c259d907517dcc0ffefcd4e30276ae29 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 29 Aug 2012 06:49:16 +0000 Subject: netfilter: ctnetlink: fix error return code in init path Initialize return variable before exiting on an error path. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index da4fc37..9807f32 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2790,7 +2790,8 @@ static int __init ctnetlink_init(void) goto err_unreg_subsys; } - if (register_pernet_subsys(&ctnetlink_net_ops)) { + ret = register_pernet_subsys(&ctnetlink_net_ops); + if (ret < 0) { pr_err("ctnetlink_init: cannot register pernet operations\n"); goto err_unreg_exp_subsys; } -- cgit v0.10.2 From 6fc09f10f12477bdaa54e94f9cb428bef6d81315 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 29 Aug 2012 06:49:17 +0000 Subject: netfilter: nfnetlink_log: fix error return code in init path Initialize return variable before exiting on an error path. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 592091c1..14e2f39 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -996,8 +996,10 @@ static int __init nfnetlink_log_init(void) #ifdef CONFIG_PROC_FS if (!proc_create("nfnetlink_log", 0440, - proc_net_netfilter, &nful_file_ops)) + proc_net_netfilter, &nful_file_ops)) { + status = -ENOMEM; goto cleanup_logger; + } #endif return status; -- cgit v0.10.2 From 497dcf6fc355f0734faf851662b6957386715d24 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 29 Aug 2012 18:58:01 -0700 Subject: ARM: shmobile: marzen: fixup smsc911x id for regulator dummy_supplies for smsc911x are registered as "smsc911x". smsc911x driver needs id = -1 Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index 3a528cf..fcf5a47 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -67,7 +67,7 @@ static struct smsc911x_platform_config smsc911x_platdata = { static struct platform_device eth_device = { .name = "smsc911x", - .id = 0, + .id = -1, .dev = { .platform_data = &smsc911x_platdata, }, -- cgit v0.10.2 From 015618b902ae8e28705b7af9b4668615fea48ddd Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 29 Aug 2012 13:17:05 +0200 Subject: ALSA: snd-usb: Fix URB cancellation at stream start Commit e9ba389c5 ("ALSA: usb-audio: Fix scheduling-while-atomic bug in PCM capture stream") fixed a scheduling-while-atomic bug that happened when snd_usb_endpoint_start was called from the trigger callback, which is an atmic context. However, the patch breaks the idea of the endpoints reference counting, which is the reason why the driver has been refactored lately. Revert that commit and let snd_usb_endpoint_start() take care of the URB cancellation again. As this function is called from both atomic and non-atomic context, add a flag to denote whether the function may sleep. Signed-off-by: Daniel Mack Cc: stable@kernel.org [3.5+] Signed-off-by: Takashi Iwai diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index c411812..b896c55 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -799,7 +799,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, /** * snd_usb_endpoint_start: start an snd_usb_endpoint * - * @ep: the endpoint to start + * @ep: the endpoint to start + * @can_sleep: flag indicating whether the operation is executed in + * non-atomic context * * A call to this function will increment the use count of the endpoint. * In case it is not already running, the URBs for this endpoint will be @@ -809,7 +811,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, * * Returns an error if the URB submission failed, 0 in all other cases. */ -int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep) { int err; unsigned int i; @@ -821,6 +823,11 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (++ep->use_count != 1) return 0; + /* just to be sure */ + deactivate_urbs(ep, 0, can_sleep); + if (can_sleep) + wait_clear_urbs(ep); + ep->active_mask = 0; ep->unlink_mask = 0; ep->phase = 0; diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index ee2723f..a8e60c1 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -13,7 +13,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, struct audioformat *fmt, struct snd_usb_endpoint *sync_ep); -int snd_usb_endpoint_start(struct snd_usb_endpoint *ep); +int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep); void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, int force, int can_sleep, int wait); int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 62ec808..1546577 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -212,7 +212,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, } } -static int start_endpoints(struct snd_usb_substream *subs) +static int start_endpoints(struct snd_usb_substream *subs, int can_sleep) { int err; @@ -225,7 +225,7 @@ static int start_endpoints(struct snd_usb_substream *subs) snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep); ep->data_subs = subs; - err = snd_usb_endpoint_start(ep); + err = snd_usb_endpoint_start(ep, can_sleep); if (err < 0) { clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); return err; @@ -239,7 +239,7 @@ static int start_endpoints(struct snd_usb_substream *subs) snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep); ep->sync_slave = subs->data_endpoint; - err = snd_usb_endpoint_start(ep); + err = snd_usb_endpoint_start(ep, can_sleep); if (err < 0) { clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); return err; @@ -544,13 +544,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) subs->last_frame_number = 0; runtime->delay = 0; - /* clear the pending deactivation on the target EPs */ - deactivate_endpoints(subs); - /* for playback, submit the URBs now; otherwise, the first hwptr_done * updates for all URBs would happen at the same time when starting */ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) - return start_endpoints(subs); + return start_endpoints(subs, 1); return 0; } @@ -1175,7 +1172,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream switch (cmd) { case SNDRV_PCM_TRIGGER_START: - err = start_endpoints(subs); + err = start_endpoints(subs, 0); if (err < 0) return err; -- cgit v0.10.2 From 6c7080a61fc7b46b3ac8573952b5a3e9d5f68bc4 Mon Sep 17 00:00:00 2001 From: Mark Asselstine Date: Wed, 8 Aug 2012 13:14:36 -0400 Subject: firmware: fix directory creation rule matching with make 3.82 Attempting to run 'firmware_install' with CONFIG_USB_SERIAL_TI=y when using make 3.82 results in an error make[2]: *** No rule to make target `/lib/firmware/./', needed by `/lib/firmware/ti_3410.fw'. Stop. It turns out make 3.82 is picky when matching directory names with trailing slashes as a result, where make 3.81 would handle this correctly make 3.82 does not find the rule needed to create the directory. The './' seen in the error is added by $(dir) for firmware which resides in the base firmware src directory, such as ti_3410.fw.ihex. By performing $(dir) after we prepend the $(INSTALL_FW_PATH) we can ensure we don't end up with a './' in the middle of the path and the directory will be properly created. This change works with make 3.81 and should work with previous versions as well. Signed-off-by: Mark Asselstine Signed-off-by: Michal Marek diff --git a/scripts/Makefile.fwinst b/scripts/Makefile.fwinst index 6bf8e87..c3f69ae 100644 --- a/scripts/Makefile.fwinst +++ b/scripts/Makefile.fwinst @@ -42,7 +42,7 @@ quiet_cmd_install = INSTALL $(subst $(srctree)/,,$@) $(installed-fw-dirs): $(call cmd,mkdir) -$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $(INSTALL_FW_PATH)/$$(dir %) +$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $$(dir $(INSTALL_FW_PATH)/%) $(call cmd,install) PHONY += __fw_install __fw_modinst FORCE -- cgit v0.10.2 From 3683243b2c551e58082b179fd153c7d43ddc503b Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 22 Aug 2012 00:26:47 +0000 Subject: xen-netfront: use __pskb_pull_tail to ensure linear area is big enough on RX I'm slightly concerned by the "only in exceptional circumstances" comment on __pskb_pull_tail but the structure of an skb just created by netfront shouldn't hit any of the especially slow cases. This approach still does slightly more work than the old way, since if we pull up the entire first frag we now have to shuffle everything down where before we just received into the right place in the first place. Signed-off-by: Ian Campbell Cc: Konrad Rzeszutek Wilk Cc: Jeremy Fitzhardinge Cc: Mel Gorman Cc: xen-devel@lists.xensource.com Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Tested-by: Konrad Rzeszutek Wilk Acked-by: Konrad Rzeszutek Wilk Signed-off-by: David S. Miller diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 3089990..650f79a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -57,8 +57,7 @@ static const struct ethtool_ops xennet_ethtool_ops; struct netfront_cb { - struct page *page; - unsigned offset; + int pull_to; }; #define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb)) @@ -867,15 +866,9 @@ static int handle_incoming_queue(struct net_device *dev, struct sk_buff *skb; while ((skb = __skb_dequeue(rxq)) != NULL) { - struct page *page = NETFRONT_SKB_CB(skb)->page; - void *vaddr = page_address(page); - unsigned offset = NETFRONT_SKB_CB(skb)->offset; - - memcpy(skb->data, vaddr + offset, - skb_headlen(skb)); + int pull_to = NETFRONT_SKB_CB(skb)->pull_to; - if (page != skb_frag_page(&skb_shinfo(skb)->frags[0])) - __free_page(page); + __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); /* Ethernet work: Delayed to here as it peeks the header. */ skb->protocol = eth_type_trans(skb, dev); @@ -913,7 +906,6 @@ static int xennet_poll(struct napi_struct *napi, int budget) struct sk_buff_head errq; struct sk_buff_head tmpq; unsigned long flags; - unsigned int len; int err; spin_lock(&np->rx_lock); @@ -955,24 +947,13 @@ err: } } - NETFRONT_SKB_CB(skb)->page = - skb_frag_page(&skb_shinfo(skb)->frags[0]); - NETFRONT_SKB_CB(skb)->offset = rx->offset; - - len = rx->status; - if (len > RX_COPY_THRESHOLD) - len = RX_COPY_THRESHOLD; - skb_put(skb, len); + NETFRONT_SKB_CB(skb)->pull_to = rx->status; + if (NETFRONT_SKB_CB(skb)->pull_to > RX_COPY_THRESHOLD) + NETFRONT_SKB_CB(skb)->pull_to = RX_COPY_THRESHOLD; - if (rx->status > len) { - skb_shinfo(skb)->frags[0].page_offset = - rx->offset + len; - skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status - len); - skb->data_len = rx->status - len; - } else { - __skb_fill_page_desc(skb, 0, NULL, 0, 0); - skb_shinfo(skb)->nr_frags = 0; - } + skb_shinfo(skb)->frags[0].page_offset = rx->offset; + skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status); + skb->data_len = rx->status; i = xennet_fill_frags(np, skb, &tmpq); @@ -999,7 +980,7 @@ err: * receive throughout using the standard receive * buffer size was cut by 25%(!!!). */ - skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len); + skb->truesize += skb->data_len - RX_COPY_THRESHOLD; skb->len += skb->data_len; if (rx->flags & XEN_NETRXF_csum_blank) -- cgit v0.10.2 From 3f509c689a07a4aa989b426893d8491a7ffcc410 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 29 Aug 2012 15:24:09 +0000 Subject: netfilter: nf_nat_sip: fix incorrect handling of EBUSY for RTCP expectation We're hitting bug while trying to reinsert an already existing expectation: kernel BUG at kernel/timer.c:895! invalid opcode: 0000 [#1] SMP [...] Call Trace: [] nf_ct_expect_related_report+0x4a0/0x57a [nf_conntrack] [] ? in4_pton+0x72/0x131 [] ip_nat_sdp_media+0xeb/0x185 [nf_nat_sip] [] set_expected_rtp_rtcp+0x32d/0x39b [nf_conntrack_sip] [] process_sdp+0x30c/0x3ec [nf_conntrack_sip] [] ? irq_exit+0x9a/0x9c [] ? ip_nat_sdp_media+0x185/0x185 [nf_nat_sip] We have to remove the RTP expectation if the RTCP expectation hits EBUSY since we keep trying with other ports until we succeed. Reported-by: Rafal Fitt Signed-off-by: Pablo Neira Ayuso diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 4ad9cf1..9c87cde 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -502,7 +502,10 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff, ret = nf_ct_expect_related(rtcp_exp); if (ret == 0) break; - else if (ret != -EBUSY) { + else if (ret == -EBUSY) { + nf_ct_unexpect_related(rtp_exp); + continue; + } else if (ret < 0) { nf_ct_unexpect_related(rtp_exp); port = 0; break; -- cgit v0.10.2 From e2c53be223aca36cf93eb6a0f6bafa079e78f52b Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 23 Aug 2012 21:46:25 +0000 Subject: gianfar: fix default tx vlan offload feature flag Commit - "b852b72 gianfar: fix bug caused by 87c288c6e9aa31720b72e2bc2d665e24e1653c3e" disables by default (on mac init) the hw vlan tag insertion. The "features" flags were not updated to reflect this, and "ethtool -K" shows tx-vlan-offload to be "on" by default. Cc: Sebastian Poehn Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 4605f72..d3233f5 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1041,7 +1041,7 @@ static int gfar_probe(struct platform_device *ofdev) if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->features |= NETIF_F_HW_VLAN_RX; } if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { -- cgit v0.10.2 From 99469c32f79a32d8481f87be0d3c66dad286f4ec Mon Sep 17 00:00:00 2001 From: "xeb@mail.ru" Date: Fri, 24 Aug 2012 01:07:38 +0000 Subject: l2tp: avoid to use synchronize_rcu in tunnel free function Avoid to use synchronize_rcu in l2tp_tunnel_free because context may be atomic. Signed-off-by: Dmitry Kozlov Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 393355d..513cab0 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1347,11 +1347,10 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) /* Remove from tunnel list */ spin_lock_bh(&pn->l2tp_tunnel_list_lock); list_del_rcu(&tunnel->list); + kfree_rcu(tunnel, rcu); spin_unlock_bh(&pn->l2tp_tunnel_list_lock); - synchronize_rcu(); atomic_dec(&l2tp_tunnel_count); - kfree(tunnel); } /* Create a socket for the tunnel, if one isn't set up by diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index a38ec6c..56d583e 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -163,6 +163,7 @@ struct l2tp_tunnel_cfg { struct l2tp_tunnel { int magic; /* Should be L2TP_TUNNEL_MAGIC */ + struct rcu_head rcu; rwlock_t hlist_lock; /* protect session_hlist */ struct hlist_head session_hlist[L2TP_HASH_SIZE]; /* hashed list of sessions, -- cgit v0.10.2 From d821a4c4d11ad160925dab2bb009b8444beff484 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 24 Aug 2012 20:38:11 +0000 Subject: e1000e: DoS while TSO enabled caused by link partner with small MSS With a low enough MSS on the link partner and TSO enabled locally, the networking stack can periodically send a very large (e.g. 64KB) TCP message for which the driver will attempt to use more Tx descriptors than are available by default in the Tx ring. This is due to a workaround in the code that imposes a limit of only 4 MSS-sized segments per descriptor which appears to be a carry-over from the older e1000 driver and may be applicable only to some older PCI or PCIx parts which are not supported in e1000e. When the driver gets a message that is too large to fit across the configured number of Tx descriptors, it stops the upper stack from queueing any more and gets stuck in this state. After a timeout, the upper stack assumes the adapter is hung and calls the driver to reset it. Remove the unnecessary limitation of using up to only 4 MSS-sized segments per Tx descriptor, and put in a hard failure test to catch when attempting to check for message sizes larger than would fit in the whole Tx ring. Refactor the remaining logic that limits the size of data per Tx descriptor from a seemingly arbitrary 8KB to a limit based on the dynamic size of the Tx packet buffer as described in the hardware specification. Also, fix the logic in the check for space in the Tx ring for the next largest possible packet after the current one has been successfully queued for transmit, and use the appropriate defines for default ring sizes in e1000_probe instead of magic values. This issue goes back to the introduction of e1000e in 2.6.24 when it was split off from e1000. Reported-by: Ben Hutchings Signed-off-by: Bruce Allan Cc: Stable [2.6.24+] Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index cd15332..cb3356c 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -310,6 +310,7 @@ struct e1000_adapter { */ struct e1000_ring *tx_ring /* One per active queue */ ____cacheline_aligned_in_smp; + u32 tx_fifo_limit; struct napi_struct napi; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 46c3b1f..d01a099 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3517,6 +3517,15 @@ void e1000e_reset(struct e1000_adapter *adapter) } /* + * Alignment of Tx data is on an arbitrary byte boundary with the + * maximum size per Tx descriptor limited only to the transmit + * allocation of the packet buffer minus 96 bytes with an upper + * limit of 24KB due to receive synchronization limitations. + */ + adapter->tx_fifo_limit = min_t(u32, ((er32(PBA) >> 16) << 10) - 96, + 24 << 10); + + /* * Disable Adaptive Interrupt Moderation if 2 full packets cannot * fit in receive buffer. */ @@ -4785,12 +4794,9 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb) return 1; } -#define E1000_MAX_PER_TXD 8192 -#define E1000_MAX_TXD_PWR 12 - static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb, unsigned int first, unsigned int max_per_txd, - unsigned int nr_frags, unsigned int mss) + unsigned int nr_frags) { struct e1000_adapter *adapter = tx_ring->adapter; struct pci_dev *pdev = adapter->pdev; @@ -5023,20 +5029,19 @@ static int __e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size) static int e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size) { + BUG_ON(size > tx_ring->count); + if (e1000_desc_unused(tx_ring) >= size) return 0; return __e1000_maybe_stop_tx(tx_ring, size); } -#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1) static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_ring *tx_ring = adapter->tx_ring; unsigned int first; - unsigned int max_per_txd = E1000_MAX_PER_TXD; - unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; unsigned int len = skb_headlen(skb); unsigned int nr_frags; @@ -5056,18 +5061,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, } mss = skb_shinfo(skb)->gso_size; - /* - * The controller does a simple calculation to - * make sure there is enough room in the FIFO before - * initiating the DMA for each buffer. The calc is: - * 4 = ceil(buffer len/mss). To make sure we don't - * overrun the FIFO, adjust the max buffer len if mss - * drops. - */ if (mss) { u8 hdr_len; - max_per_txd = min(mss << 2, max_per_txd); - max_txd_pwr = fls(max_per_txd) - 1; /* * TSO Workaround for 82571/2/3 Controllers -- if skb->data @@ -5097,12 +5092,12 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, count++; count++; - count += TXD_USE_COUNT(len, max_txd_pwr); + count += DIV_ROUND_UP(len, adapter->tx_fifo_limit); nr_frags = skb_shinfo(skb)->nr_frags; for (f = 0; f < nr_frags; f++) - count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->frags[f]), - max_txd_pwr); + count += DIV_ROUND_UP(skb_frag_size(&skb_shinfo(skb)->frags[f]), + adapter->tx_fifo_limit); if (adapter->hw.mac.tx_pkt_filtering) e1000_transfer_dhcp_info(adapter, skb); @@ -5144,15 +5139,18 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, tx_flags |= E1000_TX_FLAGS_NO_FCS; /* if count is 0 then mapping error has occurred */ - count = e1000_tx_map(tx_ring, skb, first, max_per_txd, nr_frags, mss); + count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit, + nr_frags); if (count) { skb_tx_timestamp(skb); netdev_sent_queue(netdev, skb->len); e1000_tx_queue(tx_ring, tx_flags, count); /* Make sure there is space in the ring for the next send. */ - e1000_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 2); - + e1000_maybe_stop_tx(tx_ring, + (MAX_SKB_FRAGS * + DIV_ROUND_UP(PAGE_SIZE, + adapter->tx_fifo_limit) + 2)); } else { dev_kfree_skb_any(skb); tx_ring->buffer_info[first].time_stamp = 0; @@ -6327,8 +6325,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->hw.phy.autoneg_advertised = 0x2f; /* ring size defaults */ - adapter->rx_ring->count = 256; - adapter->tx_ring->count = 256; + adapter->rx_ring->count = E1000_DEFAULT_RXD; + adapter->tx_ring->count = E1000_DEFAULT_TXD; /* * Initial Wake on LAN setting - If APM wake is enabled in -- cgit v0.10.2 From acbb219d5f53821b2d0080d047800410c0420ea1 Mon Sep 17 00:00:00 2001 From: Francesco Ruggeri Date: Fri, 24 Aug 2012 07:38:35 +0000 Subject: net: ipv4: ipmr_expire_timer causes crash when removing net namespace When tearing down a net namespace, ipv4 mr_table structures are freed without first deactivating their timers. This can result in a crash in run_timer_softirq. This patch mimics the corresponding behaviour in ipv6. Locking and synchronization seem to be adequate. We are about to kfree mrt, so existing code should already make sure that no other references to mrt are pending or can be created by incoming traffic. The functions invoked here do not cause new references to mrt or other race conditions to be created. Invoking del_timer_sync guarantees that ipmr_expire_timer is inactive. Both ipmr_expire_process (whose completion we may have to wait in del_timer_sync) and mroute_clean_tables internally use mfc_unres_lock or other synchronizations when needed, and they both only modify mrt. Tested in Linux 3.4.8. Signed-off-by: Francesco Ruggeri Signed-off-by: David S. Miller diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 8eec8f4..ebdf06f 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -124,6 +124,8 @@ static DEFINE_SPINLOCK(mfc_unres_lock); static struct kmem_cache *mrt_cachep __read_mostly; static struct mr_table *ipmr_new_table(struct net *net, u32 id); +static void ipmr_free_table(struct mr_table *mrt); + static int ip_mr_forward(struct net *net, struct mr_table *mrt, struct sk_buff *skb, struct mfc_cache *cache, int local); @@ -131,6 +133,7 @@ static int ipmr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, vifi_t vifi, int assert); static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); +static void mroute_clean_tables(struct mr_table *mrt); static void ipmr_expire_process(unsigned long arg); #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES @@ -271,7 +274,7 @@ static void __net_exit ipmr_rules_exit(struct net *net) list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { list_del(&mrt->list); - kfree(mrt); + ipmr_free_table(mrt); } fib_rules_unregister(net->ipv4.mr_rules_ops); } @@ -299,7 +302,7 @@ static int __net_init ipmr_rules_init(struct net *net) static void __net_exit ipmr_rules_exit(struct net *net) { - kfree(net->ipv4.mrt); + ipmr_free_table(net->ipv4.mrt); } #endif @@ -336,6 +339,13 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) return mrt; } +static void ipmr_free_table(struct mr_table *mrt) +{ + del_timer_sync(&mrt->ipmr_expire_timer); + mroute_clean_tables(mrt); + kfree(mrt); +} + /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) -- cgit v0.10.2 From 5c879d2094946081af934739850c7260e8b25d3c Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Sun, 26 Aug 2012 00:35:45 +0000 Subject: bnx2x: fix 57840_MF pci id Commit c3def943c7117d42caaed3478731ea7c3c87190e have added support for new pci ids of the 57840 board, while failing to change the obsolete value in 'pci_ids.h'. This patch does so, allowing the probe of such devices. Signed-off-by: Yuval Mintz Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index fc35260..6b4565c 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2149,7 +2149,7 @@ #define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 #define PCI_DEVICE_ID_NX2_57800_VF 0x16a9 #define PCI_DEVICE_ID_NX2_5706S 0x16aa -#define PCI_DEVICE_ID_NX2_57840_MF 0x16ab +#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4 #define PCI_DEVICE_ID_NX2_5708S 0x16ac #define PCI_DEVICE_ID_NX2_57840_VF 0x16ad #define PCI_DEVICE_ID_NX2_57810_MF 0x16ae -- cgit v0.10.2 From c5ae7d41927dbd208c885d4794e30617ad6cdf12 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 28 Aug 2012 12:33:07 +0000 Subject: ipv4: must use rcu protection while calling fib_lookup Following lockdep splat was reported by Pavel Roskin : [ 1570.586223] =============================== [ 1570.586225] [ INFO: suspicious RCU usage. ] [ 1570.586228] 3.6.0-rc3-wl-main #98 Not tainted [ 1570.586229] ------------------------------- [ 1570.586231] /home/proski/src/linux/net/ipv4/route.c:645 suspicious rcu_dereference_check() usage! [ 1570.586233] [ 1570.586233] other info that might help us debug this: [ 1570.586233] [ 1570.586236] [ 1570.586236] rcu_scheduler_active = 1, debug_locks = 0 [ 1570.586238] 2 locks held by Chrome_IOThread/4467: [ 1570.586240] #0: (slock-AF_INET){+.-...}, at: [] release_sock+0x2c/0xa0 [ 1570.586253] #1: (fnhe_lock){+.-...}, at: [] update_or_create_fnhe+0x2c/0x270 [ 1570.586260] [ 1570.586260] stack backtrace: [ 1570.586263] Pid: 4467, comm: Chrome_IOThread Not tainted 3.6.0-rc3-wl-main #98 [ 1570.586265] Call Trace: [ 1570.586271] [] lockdep_rcu_suspicious+0xfd/0x130 [ 1570.586275] [] update_or_create_fnhe+0x15c/0x270 [ 1570.586278] [] __ip_rt_update_pmtu+0x73/0xb0 [ 1570.586282] [] ip_rt_update_pmtu+0x29/0x90 [ 1570.586285] [] inet_csk_update_pmtu+0x2c/0x80 [ 1570.586290] [] tcp_v4_mtu_reduced+0x2e/0xc0 [ 1570.586293] [] tcp_release_cb+0xa4/0xb0 [ 1570.586296] [] release_sock+0x55/0xa0 [ 1570.586300] [] tcp_sendmsg+0x4af/0xf50 [ 1570.586305] [] inet_sendmsg+0x120/0x230 [ 1570.586308] [] ? inet_sk_rebuild_header+0x40/0x40 [ 1570.586312] [] ? sock_update_classid+0xbd/0x3b0 [ 1570.586315] [] ? sock_update_classid+0x130/0x3b0 [ 1570.586320] [] do_sock_write+0xc5/0xe0 [ 1570.586323] [] sock_aio_write+0x53/0x80 [ 1570.586328] [] do_sync_write+0xa3/0xe0 [ 1570.586332] [] vfs_write+0x165/0x180 [ 1570.586335] [] sys_write+0x45/0x90 [ 1570.586340] [] system_call_fastpath+0x16/0x1b Signed-off-by: Eric Dumazet Reported-by: Pavel Roskin Signed-off-by: David S. Miller diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 24fd4c5..82cf2a7 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -934,12 +934,14 @@ static u32 __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) if (mtu < ip_rt_min_pmtu) mtu = ip_rt_min_pmtu; + rcu_read_lock(); if (fib_lookup(dev_net(rt->dst.dev), fl4, &res) == 0) { struct fib_nh *nh = &FIB_RES_NH(res); update_or_create_fnhe(nh, fl4->daddr, 0, mtu, jiffies + ip_rt_mtu_expires); } + rcu_read_unlock(); return mtu; } -- cgit v0.10.2 From 26614ba5445fe31a69068a5e94266fa08b4ee345 Mon Sep 17 00:00:00 2001 From: Merav Sicron Date: Mon, 27 Aug 2012 03:26:19 +0000 Subject: bnx2x: Move netif_napi_add to the open call Move netif_napi_add for all queues from the probe call to the open call, to avoid the case that napi objects are added for queues that may eventually not be initialized and activated. With the former behavior, the driver could crash when netpoll was calling ndo_poll_controller. Signed-off-by: Merav Sicron Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 463b9ec..6d1a24a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1708,9 +1708,6 @@ struct bnx2x_func_init_params { continue; \ else -#define for_each_napi_rx_queue(bp, var) \ - for ((var) = 0; (var) < bp->num_napi_queues; (var)++) - /* Skip OOO FP */ #define for_each_tx_queue(bp, var) \ for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index e879e19..af20c6e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2046,6 +2046,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) */ bnx2x_setup_tc(bp->dev, bp->max_cos); + /* Add all NAPI objects */ + bnx2x_add_all_napi(bp); bnx2x_napi_enable(bp); /* set pf load just before approaching the MCP */ @@ -2408,6 +2410,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) /* Disable HW interrupts, NAPI */ bnx2x_netif_stop(bp, 1); + /* Delete all NAPI objects */ + bnx2x_del_all_napi(bp); /* Release IRQs */ bnx2x_free_irq(bp); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index dfa757e..21b5532 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -792,7 +792,7 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp) bp->num_napi_queues = bp->num_queues; /* Add NAPI objects */ - for_each_napi_rx_queue(bp, i) + for_each_rx_queue(bp, i) netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), bnx2x_poll, BNX2X_NAPI_WEIGHT); } @@ -801,7 +801,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp) { int i; - for_each_napi_rx_queue(bp, i) + for_each_rx_queue(bp, i) netif_napi_del(&bnx2x_fp(bp, i, napi)); } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index fc4e0e3..c37a68d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -2888,11 +2888,9 @@ static void bnx2x_get_channels(struct net_device *dev, */ static void bnx2x_change_num_queues(struct bnx2x *bp, int num_rss) { - bnx2x_del_all_napi(bp); bnx2x_disable_msi(bp); BNX2X_NUM_QUEUES(bp) = num_rss + NON_ETH_CONTEXT_USE; bnx2x_set_int_mode(bp); - bnx2x_add_all_napi(bp); } /** diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 02b5a34..5b42275 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -8427,6 +8427,8 @@ unload_error: /* Disable HW interrupts, NAPI */ bnx2x_netif_stop(bp, 1); + /* Delete all NAPI objects */ + bnx2x_del_all_napi(bp); /* Release IRQs */ bnx2x_free_irq(bp); @@ -11899,9 +11901,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, */ bnx2x_set_int_mode(bp); - /* Add all NAPI objects */ - bnx2x_add_all_napi(bp); - rc = register_netdev(dev); if (rc) { dev_err(&pdev->dev, "Cannot register net device\n"); @@ -11976,9 +11975,6 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev) unregister_netdev(dev); - /* Delete all NAPI objects */ - bnx2x_del_all_napi(bp); - /* Power on: we can't let PCI layer write to us while we are in D3 */ bnx2x_set_power_state(bp, PCI_D0); @@ -12025,6 +12021,8 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp) bnx2x_tx_disable(bp); bnx2x_netif_stop(bp, 0); + /* Delete all NAPI objects */ + bnx2x_del_all_napi(bp); del_timer_sync(&bp->timer); -- cgit v0.10.2 From 14a15d618743ebc4936fe03073bf0c75024d3a07 Mon Sep 17 00:00:00 2001 From: Merav Sicron Date: Mon, 27 Aug 2012 03:26:20 +0000 Subject: bnx2x: Correct the ndo_poll_controller call This patch correct poll_bnx2x (ndo_poll_controller call) which was not functioning well with MSI-X. Signed-off-by: Merav Sicron Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 5b42275..2105498 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -11231,10 +11231,12 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static void poll_bnx2x(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); + int i; - disable_irq(bp->pdev->irq); - bnx2x_interrupt(bp->pdev->irq, dev); - enable_irq(bp->pdev->irq); + for_each_eth_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + napi_schedule(&bnx2x_fp(bp, fp->index, napi)); + } } #endif -- cgit v0.10.2 From 52bd138d616409a45bbb32bd3536cbdadc524de6 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:22 -0700 Subject: ARM: OMAP2+: gpmc: update nand register helper Provide helper function for updating NAND register details for the necessary chip select. NAND drivers platform data can be updated with this information so that NAND driver can handle GPMC NAND operations by itself. Signed-off-by: Afzal Mohammed Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index b2b5759..5cce9b0 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -682,6 +682,26 @@ int gpmc_prefetch_reset(int cs) } EXPORT_SYMBOL(gpmc_prefetch_reset); +void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs) +{ + reg->gpmc_status = gpmc_base + GPMC_STATUS; + reg->gpmc_nand_command = gpmc_base + GPMC_CS0_OFFSET + + GPMC_CS_NAND_COMMAND + GPMC_CS_SIZE * cs; + reg->gpmc_nand_address = gpmc_base + GPMC_CS0_OFFSET + + GPMC_CS_NAND_ADDRESS + GPMC_CS_SIZE * cs; + reg->gpmc_nand_data = gpmc_base + GPMC_CS0_OFFSET + + GPMC_CS_NAND_DATA + GPMC_CS_SIZE * cs; + reg->gpmc_prefetch_config1 = gpmc_base + GPMC_PREFETCH_CONFIG1; + reg->gpmc_prefetch_config2 = gpmc_base + GPMC_PREFETCH_CONFIG2; + reg->gpmc_prefetch_control = gpmc_base + GPMC_PREFETCH_CONTROL; + reg->gpmc_prefetch_status = gpmc_base + GPMC_PREFETCH_STATUS; + reg->gpmc_ecc_config = gpmc_base + GPMC_ECC_CONFIG; + reg->gpmc_ecc_control = gpmc_base + GPMC_ECC_CONTROL; + reg->gpmc_ecc_size_config = gpmc_base + GPMC_ECC_SIZE_CONFIG; + reg->gpmc_ecc1_result = gpmc_base + GPMC_ECC1_RESULT; + reg->gpmc_bch_result0 = gpmc_base + GPMC_ECC_BCH_RESULT_0; +} + static void __init gpmc_mem_init(void) { int cs; diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h index f37764a..06198a5 100644 --- a/arch/arm/plat-omap/include/plat/gpmc.h +++ b/arch/arm/plat-omap/include/plat/gpmc.h @@ -133,6 +133,24 @@ struct gpmc_timings { u16 wr_data_mux_bus; /* WRDATAONADMUXBUS */ }; +struct gpmc_nand_regs { + void __iomem *gpmc_status; + void __iomem *gpmc_nand_command; + void __iomem *gpmc_nand_address; + void __iomem *gpmc_nand_data; + void __iomem *gpmc_prefetch_config1; + void __iomem *gpmc_prefetch_config2; + void __iomem *gpmc_prefetch_control; + void __iomem *gpmc_prefetch_status; + void __iomem *gpmc_ecc_config; + void __iomem *gpmc_ecc_control; + void __iomem *gpmc_ecc_size_config; + void __iomem *gpmc_ecc1_result; + void __iomem *gpmc_bch_result0; +}; + +extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs); + extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns); extern unsigned int gpmc_ps_to_ticks(unsigned int time_ps); extern unsigned int gpmc_ticks_to_ns(unsigned int ticks); -- cgit v0.10.2 From d126d0158b98469b833bcd5214bc909f164a0033 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:22 -0700 Subject: ARM: OMAP2+: gpmc-nand: update gpmc-nand regs GPMC has NAND registers, update nand platform data with those details so that NAND driver can configure those by itself instead of using exported symbols. Signed-off-by: Afzal Mohammed Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index 386dec8..d4e803c 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -108,6 +108,8 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data) gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_RDY_BSY, 1); } + gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs); + err = platform_device_register(&gpmc_nand_device); if (err < 0) { dev_err(dev, "Unable to register NAND device\n"); diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h index 67fc506..86e4d9c 100644 --- a/arch/arm/plat-omap/include/plat/nand.h +++ b/arch/arm/plat-omap/include/plat/nand.h @@ -29,6 +29,7 @@ struct omap_nand_platform_data { unsigned long phys_base; int devsize; enum omap_ecc ecc_opt; + struct gpmc_nand_regs reg; }; /* minimum size for IO mapping */ -- cgit v0.10.2 From 65b97cf6b8deca3ad7a3e00e8316bb89617190fb Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:22 -0700 Subject: mtd: nand: omap2: handle nand on gpmc GPMC platform initialization has been modified to fill NAND platform data with GPMC NAND register details. As these registers are accessible in NAND driver itself, configure NAND in GPMC by itself. Modified prefetch and ecc functions are logically same as the corresponding exported symbols from GPMC code. Note: Verfying that other CS have not yet enabled for prefetch & ecc has to be incorporated. Currently this causes no issues as there are no boards that use NAND on multiple CS. With ongoing GPMC driver migration, perhaps it would be better to consider NAND connected on multiple CS as a single peripheral using multiple CS. This would make handling multiple CS issues easier. Signed-off-by: Afzal Mohammed Acked-by: Artem Bityutskiy Signed-off-by: Tony Lindgren diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ac4fd75..52fc089 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -101,6 +101,16 @@ #define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) #define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) +#define PREFETCH_CONFIG1_CS_SHIFT 24 +#define ECC_CONFIG_CS_SHIFT 1 +#define CS_MASK 0x7 +#define ENABLE_PREFETCH (0x1 << 7) +#define DMA_MPU_MODE_SHIFT 2 +#define ECCSIZE1_SHIFT 22 +#define ECC1RESULTSIZE 0x1 +#define ECCCLEAR 0x100 +#define ECC1 0x1 + /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; /* Define some generic bad / good block scan pattern which are used @@ -133,6 +143,7 @@ struct omap_nand_info { } iomode; u_char *buf; int buf_len; + struct gpmc_nand_regs reg; #ifdef CONFIG_MTD_NAND_OMAP_BCH struct bch_control *bch; @@ -141,6 +152,63 @@ struct omap_nand_info { }; /** + * omap_prefetch_enable - configures and starts prefetch transfer + * @cs: cs (chip select) number + * @fifo_th: fifo threshold to be used for read/ write + * @dma_mode: dma mode enable (1) or disable (0) + * @u32_count: number of bytes to be transferred + * @is_write: prefetch read(0) or write post(1) mode + */ +static int omap_prefetch_enable(int cs, int fifo_th, int dma_mode, + unsigned int u32_count, int is_write, struct omap_nand_info *info) +{ + u32 val; + + if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) + return -1; + + if (readl(info->reg.gpmc_prefetch_control)) + return -EBUSY; + + /* Set the amount of bytes to be prefetched */ + writel(u32_count, info->reg.gpmc_prefetch_config2); + + /* Set dma/mpu mode, the prefetch read / post write and + * enable the engine. Set which cs is has requested for. + */ + val = ((cs << PREFETCH_CONFIG1_CS_SHIFT) | + PREFETCH_FIFOTHRESHOLD(fifo_th) | ENABLE_PREFETCH | + (dma_mode << DMA_MPU_MODE_SHIFT) | (0x1 & is_write)); + writel(val, info->reg.gpmc_prefetch_config1); + + /* Start the prefetch engine */ + writel(0x1, info->reg.gpmc_prefetch_control); + + return 0; +} + +/** + * omap_prefetch_reset - disables and stops the prefetch engine + */ +static int omap_prefetch_reset(int cs, struct omap_nand_info *info) +{ + u32 config1; + + /* check if the same module/cs is trying to reset */ + config1 = readl(info->reg.gpmc_prefetch_config1); + if (((config1 >> PREFETCH_CONFIG1_CS_SHIFT) & CS_MASK) != cs) + return -EINVAL; + + /* Stop the PFPW engine */ + writel(0x0, info->reg.gpmc_prefetch_control); + + /* Reset/disable the PFPW engine */ + writel(0x0, info->reg.gpmc_prefetch_config1); + + return 0; +} + +/** * omap_hwcontrol - hardware specific access to control-lines * @mtd: MTD device structure * @cmd: command to device @@ -158,13 +226,13 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) if (cmd != NAND_CMD_NONE) { if (ctrl & NAND_CLE) - gpmc_nand_write(info->gpmc_cs, GPMC_NAND_COMMAND, cmd); + writeb(cmd, info->reg.gpmc_nand_command); else if (ctrl & NAND_ALE) - gpmc_nand_write(info->gpmc_cs, GPMC_NAND_ADDRESS, cmd); + writeb(cmd, info->reg.gpmc_nand_address); else /* NAND_NCE */ - gpmc_nand_write(info->gpmc_cs, GPMC_NAND_DATA, cmd); + writeb(cmd, info->reg.gpmc_nand_data); } } @@ -198,7 +266,8 @@ static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len) iowrite8(*p++, info->nand.IO_ADDR_W); /* wait until buffer is available for write */ do { - status = gpmc_read_status(GPMC_STATUS_BUFFER); + status = readl(info->reg.gpmc_status) & + GPMC_STATUS_BUFF_EMPTY; } while (!status); } } @@ -235,7 +304,8 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len) iowrite16(*p++, info->nand.IO_ADDR_W); /* wait until buffer is available for write */ do { - status = gpmc_read_status(GPMC_STATUS_BUFFER); + status = readl(info->reg.gpmc_status) & + GPMC_STATUS_BUFF_EMPTY; } while (!status); } } @@ -265,8 +335,8 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) } /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0); + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x0, info); if (ret) { /* PFPW engine is busy, use cpu copy method */ if (info->nand.options & NAND_BUSWIDTH_16) @@ -275,14 +345,15 @@ static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len) omap_read_buf8(mtd, (u_char *)p, len); } else { do { - r_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); + r_count = readl(info->reg.gpmc_prefetch_status); + r_count = GPMC_PREFETCH_STATUS_FIFO_CNT(r_count); r_count = r_count >> 2; ioread32_rep(info->nand.IO_ADDR_R, p, r_count); p += r_count; len -= r_count << 2; } while (len); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); } } @@ -301,6 +372,7 @@ static void omap_write_buf_pref(struct mtd_info *mtd, int i = 0, ret = 0; u16 *p = (u16 *)buf; unsigned long tim, limit; + u32 val; /* take care of subpage writes */ if (len % 2 != 0) { @@ -310,8 +382,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd, } /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1); + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX, 0x0, len, 0x1, info); if (ret) { /* PFPW engine is busy, use cpu copy method */ if (info->nand.options & NAND_BUSWIDTH_16) @@ -320,7 +392,8 @@ static void omap_write_buf_pref(struct mtd_info *mtd, omap_write_buf8(mtd, (u_char *)p, len); } else { while (len) { - w_count = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); + w_count = readl(info->reg.gpmc_prefetch_status); + w_count = GPMC_PREFETCH_STATUS_FIFO_CNT(w_count); w_count = w_count >> 1; for (i = 0; (i < w_count) && len; i++, len -= 2) iowrite16(*p++, info->nand.IO_ADDR_W); @@ -329,11 +402,14 @@ static void omap_write_buf_pref(struct mtd_info *mtd, tim = 0; limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); - while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + do { cpu_relax(); + val = readl(info->reg.gpmc_prefetch_status); + val = GPMC_PREFETCH_STATUS_COUNT(val); + } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); } } @@ -365,6 +441,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, unsigned long tim, limit; unsigned n; int ret; + u32 val; if (addr >= high_memory) { struct page *p1; @@ -396,9 +473,9 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, tx->callback_param = &info->comp; dmaengine_submit(tx); - /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); + /* configure and start prefetch transfer */ + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write, info); if (ret) /* PFPW engine is busy, use cpu copy method */ goto out_copy_unmap; @@ -410,11 +487,15 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, wait_for_completion(&info->comp); tim = 0; limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); - while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + + do { cpu_relax(); + val = readl(info->reg.gpmc_prefetch_status); + val = GPMC_PREFETCH_STATUS_COUNT(val); + } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); dma_unmap_sg(info->dma->device->dev, &sg, 1, dir); return 0; @@ -474,7 +555,8 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) u32 irq_stat; irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS); - bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); + bytes = readl(info->reg.gpmc_prefetch_status); + bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ if (irq_stat & 0x2) @@ -534,8 +616,8 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) init_completion(&info->comp); /* configure and start prefetch transfer */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0); + ret = omap_prefetch_enable(info->gpmc_cs, + PREFETCH_FIFOTHRESHOLD_MAX/2, 0x0, len, 0x0, info); if (ret) /* PFPW engine is busy, use cpu copy method */ goto out_copy; @@ -549,7 +631,7 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) wait_for_completion(&info->comp); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); return; out_copy: @@ -572,6 +654,7 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, struct omap_nand_info, mtd); int ret = 0; unsigned long tim, limit; + u32 val; if (len <= mtd->oobsize) { omap_write_buf_pref(mtd, buf, len); @@ -583,8 +666,8 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, init_completion(&info->comp); /* configure and start prefetch transfer : size=24 */ - ret = gpmc_prefetch_enable(info->gpmc_cs, - (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1); + ret = omap_prefetch_enable(info->gpmc_cs, + (PREFETCH_FIFOTHRESHOLD_MAX * 3) / 8, 0x0, len, 0x1, info); if (ret) /* PFPW engine is busy, use cpu copy method */ goto out_copy; @@ -599,11 +682,14 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, /* wait for data to flushed-out before reset the prefetch */ tim = 0; limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); - while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + do { + val = readl(info->reg.gpmc_prefetch_status); + val = GPMC_PREFETCH_STATUS_COUNT(val); cpu_relax(); + } while (val && (tim++ < limit)); /* disable and stop the PFPW engine */ - gpmc_prefetch_reset(info->gpmc_cs); + omap_prefetch_reset(info->gpmc_cs, info); return; out_copy: @@ -843,7 +929,20 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - return gpmc_calculate_ecc(info->gpmc_cs, dat, ecc_code); + u32 val; + + val = readl(info->reg.gpmc_ecc_config); + if (((val >> ECC_CONFIG_CS_SHIFT) & ~CS_MASK) != info->gpmc_cs) + return -EINVAL; + + /* read ecc result */ + val = readl(info->reg.gpmc_ecc1_result); + *ecc_code++ = val; /* P128e, ..., P1e */ + *ecc_code++ = val >> 16; /* P128o, ..., P1o */ + /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */ + *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0); + + return 0; } /** @@ -857,8 +956,34 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) mtd); struct nand_chip *chip = mtd->priv; unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; + u32 val; - gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size); + /* clear ecc and enable bits */ + val = ECCCLEAR | ECC1; + writel(val, info->reg.gpmc_ecc_control); + + /* program ecc and result sizes */ + val = ((((info->nand.ecc.size >> 1) - 1) << ECCSIZE1_SHIFT) | + ECC1RESULTSIZE); + writel(val, info->reg.gpmc_ecc_size_config); + + switch (mode) { + case NAND_ECC_READ: + case NAND_ECC_WRITE: + writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); + break; + case NAND_ECC_READSYN: + writel(ECCCLEAR, info->reg.gpmc_ecc_control); + break; + default: + dev_info(&info->pdev->dev, + "error: unrecognized Mode[%d]!\n", mode); + break; + } + + /* (ECC 16 or 8 bit col) | ( CS ) | ECC Enable */ + val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1); + writel(val, info->reg.gpmc_ecc_config); } /** @@ -886,10 +1011,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) else timeo += (HZ * 20) / 1000; - gpmc_nand_write(info->gpmc_cs, - GPMC_NAND_COMMAND, (NAND_CMD_STATUS & 0xFF)); + writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command); while (time_before(jiffies, timeo)) { - status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA); + status = readb(info->reg.gpmc_nand_data); if (status & NAND_STATUS_READY) break; cond_resched(); @@ -909,22 +1033,13 @@ static int omap_dev_ready(struct mtd_info *mtd) struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - val = gpmc_read_status(GPMC_GET_IRQ_STATUS); + val = readl(info->reg.gpmc_status); + if ((val & 0x100) == 0x100) { - /* Clear IRQ Interrupt */ - val |= 0x100; - val &= ~(0x0); - gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, val); + return 1; } else { - unsigned int cnt = 0; - while (cnt++ < 0x1FF) { - if ((val & 0x100) == 0x100) - return 0; - val = gpmc_read_status(GPMC_GET_IRQ_STATUS); - } + return 0; } - - return 1; } #ifdef CONFIG_MTD_NAND_OMAP_BCH @@ -1175,6 +1290,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->gpmc_cs = pdata->cs; info->phys_base = pdata->phys_base; + info->reg = pdata->reg; info->mtd.priv = &info->nand; info->mtd.name = dev_name(&pdev->dev); -- cgit v0.10.2 From 9222e3a7bbf3fe63629d4169b63afa27bc108ecc Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:23 -0700 Subject: ARM: OMAP2+: gpmc-nand: update resource with memory Currently omap nand driver uses a field in platform data - phys_base for passing the address space allocated by gpmc for nand. Use struct resource instead. With this change omap nand driver has to get address space from memory resource. This helps in smooth migration of gpmc to driver. Signed-off-by: Afzal Mohammed Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index d4e803c..c0320d2 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -90,12 +90,14 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data) gpmc_nand_device.dev.platform_data = gpmc_nand_data; err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, - &gpmc_nand_data->phys_base); + (unsigned long *)&gpmc_nand_resource.start); if (err < 0) { dev_err(dev, "Cannot request GPMC CS\n"); return err; } + gpmc_nand_resource.end = gpmc_nand_resource.start + NAND_IO_SIZE - 1; + /* Set timings in GPMC */ err = omap2_nand_gpmc_retime(gpmc_nand_data); if (err < 0) { -- cgit v0.10.2 From 681988ba0c369795def0346d210ce96d6177059a Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:23 -0700 Subject: ARM: OMAP2+: gpmc-onenand: provide memory as resource Currently omap onenand driver invokes gpmc_cs_request, obtains address space allocated by gpmc to onenand. Remove this, instead use resource structure; this is now updated with address space for onenand by gpmc initialization with the help of gpmc_cs_request. And remove usage of gpmc_cs_request in onenand driver. This helps in smooth migration of gpmc to driver. Signed-off-by: Afzal Mohammed Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index a0fa9bb..71d7c07 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -23,11 +23,19 @@ #include #include +#define ONENAND_IO_SIZE SZ_128K + static struct omap_onenand_platform_data *gpmc_onenand_data; +static struct resource gpmc_onenand_resource = { + .flags = IORESOURCE_MEM, +}; + static struct platform_device gpmc_onenand_device = { .name = "omap2-onenand", .id = -1, + .num_resources = 1, + .resource = &gpmc_onenand_resource, }; static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base) @@ -390,6 +398,8 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) { + int err; + gpmc_onenand_data = _onenand_data; gpmc_onenand_data->onenand_setup = gpmc_onenand_setup; gpmc_onenand_device.dev.platform_data = gpmc_onenand_data; @@ -401,8 +411,19 @@ void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) gpmc_onenand_data->flags |= ONENAND_SYNC_READ; } + err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE, + (unsigned long *)&gpmc_onenand_resource.start); + if (err < 0) { + pr_err("%s: Cannot request GPMC CS\n", __func__); + return; + } + + gpmc_onenand_resource.end = gpmc_onenand_resource.start + + ONENAND_IO_SIZE - 1; + if (platform_device_register(&gpmc_onenand_device) < 0) { - printk(KERN_ERR "Unable to register OneNAND device\n"); + pr_err("%s: Unable to register OneNAND device\n", __func__); + gpmc_cs_free(gpmc_onenand_data->cs); return; } } -- cgit v0.10.2 From 9c4c2f8b91a8bcc431d1c033e4d4455479b8183b Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:23 -0700 Subject: mtd: nand: omap2: obtain memory from resource gpmc initialization done by platform code now updates struct resource with the address space alloted for nand. Use this interface to obtain memory rather than relying on platform data field - phys_base. Signed-off-by: Afzal Mohammed Acked-by: Artem Bityutskiy Signed-off-by: Tony Lindgren diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h index 86e4d9c..290cef5 100644 --- a/arch/arm/plat-omap/include/plat/nand.h +++ b/arch/arm/plat-omap/include/plat/nand.h @@ -26,7 +26,6 @@ struct omap_nand_platform_data { bool dev_ready; int gpmc_irq; enum nand_io xfer_type; - unsigned long phys_base; int devsize; enum omap_ecc ecc_opt; struct gpmc_nand_regs reg; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 52fc089..3578c63 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -134,6 +134,7 @@ struct omap_nand_info { int gpmc_cs; unsigned long phys_base; + unsigned long mem_size; struct completion comp; struct dma_chan *dma; int gpmc_irq; @@ -1270,6 +1271,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) int i, offset; dma_cap_mask_t mask; unsigned sig; + struct resource *res; pdata = pdev->dev.platform_data; if (pdata == NULL) { @@ -1289,7 +1291,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->pdev = pdev; info->gpmc_cs = pdata->cs; - info->phys_base = pdata->phys_base; info->reg = pdata->reg; info->mtd.priv = &info->nand; @@ -1302,13 +1303,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) /* NAND write protect off */ gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0); - if (!request_mem_region(info->phys_base, NAND_IO_SIZE, + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + err = -EINVAL; + dev_err(&pdev->dev, "error getting memory resource\n"); + goto out_free_info; + } + + info->phys_base = res->start; + info->mem_size = resource_size(res); + + if (!request_mem_region(info->phys_base, info->mem_size, pdev->dev.driver->name)) { err = -EBUSY; goto out_free_info; } - info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE); + info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size); if (!info->nand.IO_ADDR_R) { err = -ENOMEM; goto out_release_mem_region; @@ -1479,7 +1490,7 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) out_release_mem_region: if (info->dma) dma_release_channel(info->dma); - release_mem_region(info->phys_base, NAND_IO_SIZE); + release_mem_region(info->phys_base, info->mem_size); out_free_info: kfree(info); -- cgit v0.10.2 From d65ccb6da60ac8f38ef6eb10ac53d94f28e0f3b1 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:23 -0700 Subject: mtd: onenand: omap2: obtain memory from resource gpmc initialization for onenand done by platform code now provides onenand address space as memory resource. Hence remove usage of gpmc_cs_request in onenand driver and obtain memory details from resource structure. Signed-off-by: Afzal Mohammed Acked-by: Artem Bityutskiy Signed-off-by: Tony Lindgren diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 398a827..3ff893d 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -48,13 +48,13 @@ #define DRIVER_NAME "omap2-onenand" -#define ONENAND_IO_SIZE SZ_128K #define ONENAND_BUFRAM_SIZE (1024 * 5) struct omap2_onenand { struct platform_device *pdev; int gpmc_cs; unsigned long phys_base; + unsigned int mem_size; int gpio_irq; struct mtd_info mtd; struct onenand_chip onenand; @@ -626,6 +626,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) struct omap2_onenand *c; struct onenand_chip *this; int r; + struct resource *res; pdata = pdev->dev.platform_data; if (pdata == NULL) { @@ -647,20 +648,24 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->gpio_irq = 0; } - r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base); - if (r < 0) { - dev_err(&pdev->dev, "Cannot request GPMC CS\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + r = -EINVAL; + dev_err(&pdev->dev, "error getting memory resource\n"); goto err_kfree; } - if (request_mem_region(c->phys_base, ONENAND_IO_SIZE, + c->phys_base = res->start; + c->mem_size = resource_size(res); + + if (request_mem_region(c->phys_base, c->mem_size, pdev->dev.driver->name) == NULL) { - dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, " - "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE); + dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, size: 0x%x\n", + c->phys_base, c->mem_size); r = -EBUSY; - goto err_free_cs; + goto err_kfree; } - c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE); + c->onenand.base = ioremap(c->phys_base, c->mem_size); if (c->onenand.base == NULL) { r = -ENOMEM; goto err_release_mem_region; @@ -776,9 +781,7 @@ err_release_gpio: err_iounmap: iounmap(c->onenand.base); err_release_mem_region: - release_mem_region(c->phys_base, ONENAND_IO_SIZE); -err_free_cs: - gpmc_cs_free(c->gpmc_cs); + release_mem_region(c->phys_base, c->mem_size); err_kfree: kfree(c); @@ -800,7 +803,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) gpio_free(c->gpio_irq); } iounmap(c->onenand.base); - release_mem_region(c->phys_base, ONENAND_IO_SIZE); + release_mem_region(c->phys_base, c->mem_size); gpmc_cs_free(c->gpmc_cs); kfree(c); -- cgit v0.10.2 From 6b6c32fc96d5a0ef1e8c5d9f1b24c3a07b878f6d Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:23 -0700 Subject: ARM: OMAP2+: gpmc: Modify interrupt handling Modify interrupt handling such that interrupts can be handled by GPMC client drivers using standard interrupt APIs rather than requiring the drivers to have knowledge about GPMC interrupt handling. Currently only NAND related interrupts has been considered (which is the case even without this change) as the only user of GPMC interrupt is NAND. Signed-off-by: Afzal Mohammed Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 5cce9b0..39c30d9 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -78,6 +78,15 @@ #define ENABLE_PREFETCH (0x1 << 7) #define DMA_MPU_MODE 2 +/* XXX: Only NAND irq has been considered,currently these are the only ones used + */ +#define GPMC_NR_IRQ 2 + +struct gpmc_client_irq { + unsigned irq; + u32 bitmask; +}; + /* Structure to save gpmc cs context */ struct gpmc_cs_config { u32 config1; @@ -105,6 +114,10 @@ struct omap3_gpmc_regs { struct gpmc_cs_config cs_context[GPMC_CS_NUM]; }; +static struct gpmc_client_irq gpmc_client_irq[GPMC_NR_IRQ]; +static struct irq_chip gpmc_irq_chip; +static unsigned gpmc_irq_start; + static struct resource gpmc_mem_root; static struct resource gpmc_cs_mem[GPMC_CS_NUM]; static DEFINE_SPINLOCK(gpmc_mem_lock); @@ -702,6 +715,97 @@ void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs) reg->gpmc_bch_result0 = gpmc_base + GPMC_ECC_BCH_RESULT_0; } +int gpmc_get_client_irq(unsigned irq_config) +{ + int i; + + if (hweight32(irq_config) > 1) + return 0; + + for (i = 0; i < GPMC_NR_IRQ; i++) + if (gpmc_client_irq[i].bitmask & irq_config) + return gpmc_client_irq[i].irq; + + return 0; +} + +static int gpmc_irq_endis(unsigned irq, bool endis) +{ + int i; + u32 regval; + + for (i = 0; i < GPMC_NR_IRQ; i++) + if (irq == gpmc_client_irq[i].irq) { + regval = gpmc_read_reg(GPMC_IRQENABLE); + if (endis) + regval |= gpmc_client_irq[i].bitmask; + else + regval &= ~gpmc_client_irq[i].bitmask; + gpmc_write_reg(GPMC_IRQENABLE, regval); + break; + } + + return 0; +} + +static void gpmc_irq_disable(struct irq_data *p) +{ + gpmc_irq_endis(p->irq, false); +} + +static void gpmc_irq_enable(struct irq_data *p) +{ + gpmc_irq_endis(p->irq, true); +} + +static void gpmc_irq_noop(struct irq_data *data) { } + +static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; } + +static int gpmc_setup_irq(int gpmc_irq) +{ + int i; + u32 regval; + + if (!gpmc_irq) + return -EINVAL; + + gpmc_irq_start = irq_alloc_descs(-1, 0, GPMC_NR_IRQ, 0); + if (IS_ERR_VALUE(gpmc_irq_start)) { + pr_err("irq_alloc_descs failed\n"); + return gpmc_irq_start; + } + + gpmc_irq_chip.name = "gpmc"; + gpmc_irq_chip.irq_startup = gpmc_irq_noop_ret; + gpmc_irq_chip.irq_enable = gpmc_irq_enable; + gpmc_irq_chip.irq_disable = gpmc_irq_disable; + gpmc_irq_chip.irq_shutdown = gpmc_irq_noop; + gpmc_irq_chip.irq_ack = gpmc_irq_noop; + gpmc_irq_chip.irq_mask = gpmc_irq_noop; + gpmc_irq_chip.irq_unmask = gpmc_irq_noop; + + gpmc_client_irq[0].bitmask = GPMC_IRQ_FIFOEVENTENABLE; + gpmc_client_irq[1].bitmask = GPMC_IRQ_COUNT_EVENT; + + for (i = 0; i < GPMC_NR_IRQ; i++) { + gpmc_client_irq[i].irq = gpmc_irq_start + i; + irq_set_chip_and_handler(gpmc_client_irq[i].irq, + &gpmc_irq_chip, handle_simple_irq); + set_irq_flags(gpmc_client_irq[i].irq, + IRQF_VALID | IRQF_NOAUTOEN); + } + + /* Disable interrupts */ + gpmc_write_reg(GPMC_IRQENABLE, 0); + + /* clear interrupts */ + regval = gpmc_read_reg(GPMC_IRQSTATUS); + gpmc_write_reg(GPMC_IRQSTATUS, regval); + + return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL); +} + static void __init gpmc_mem_init(void) { int cs; @@ -731,8 +835,8 @@ static void __init gpmc_mem_init(void) static int __init gpmc_init(void) { - u32 l, irq; - int cs, ret = -EINVAL; + u32 l; + int ret = -EINVAL; int gpmc_irq; char *ck = NULL; @@ -781,16 +885,7 @@ static int __init gpmc_init(void) gpmc_write_reg(GPMC_SYSCONFIG, l); gpmc_mem_init(); - /* initalize the irq_chained */ - irq = OMAP_GPMC_IRQ_BASE; - for (cs = 0; cs < GPMC_CS_NUM; cs++) { - irq_set_chip_and_handler(irq, &dummy_irq_chip, - handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); - irq++; - } - - ret = request_irq(gpmc_irq, gpmc_handle_irq, IRQF_SHARED, "gpmc", NULL); + ret = gpmc_setup_irq(gpmc_irq); if (ret) pr_err("gpmc: irq-%d could not claim: err %d\n", gpmc_irq, ret); @@ -800,12 +895,19 @@ postcore_initcall(gpmc_init); static irqreturn_t gpmc_handle_irq(int irq, void *dev) { - u8 cs; + int i; + u32 regval; + + regval = gpmc_read_reg(GPMC_IRQSTATUS); + + if (!regval) + return IRQ_NONE; + + for (i = 0; i < GPMC_NR_IRQ; i++) + if (regval & gpmc_client_irq[i].bitmask) + generic_handle_irq(gpmc_client_irq[i].irq); - /* check cs to invoke the irq */ - cs = ((gpmc_read_reg(GPMC_PREFETCH_CONFIG1)) >> CS_NUM_SHIFT) & 0x7; - if (OMAP_GPMC_IRQ_BASE+cs <= OMAP_GPMC_IRQ_END) - generic_handle_irq(OMAP_GPMC_IRQ_BASE+cs); + gpmc_write_reg(GPMC_IRQSTATUS, regval); return IRQ_HANDLED; } diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h index 06198a5..2e6e259 100644 --- a/arch/arm/plat-omap/include/plat/gpmc.h +++ b/arch/arm/plat-omap/include/plat/gpmc.h @@ -150,6 +150,7 @@ struct gpmc_nand_regs { }; extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs); +extern int gpmc_get_client_irq(unsigned irq_config); extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns); extern unsigned int gpmc_ps_to_ticks(unsigned int time_ps); -- cgit v0.10.2 From 2ee30f0511758c1a21d3346bb88f25f7645ba108 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:24 -0700 Subject: ARM: OMAP2+: gpmc-nand: Modify Interrupt handling Now GPMC provides its client with interrupts that can be handled using the standard interrupt API. Modify GPMC NAND setup to work with it. Also disable write protect in GPMC code, so that NAND driver can be ignorant of GPMC configuration. Signed-off-by: Afzal Mohammed Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index c0320d2..045596a 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c @@ -21,15 +21,23 @@ #include #include -static struct resource gpmc_nand_resource = { - .flags = IORESOURCE_MEM, +static struct resource gpmc_nand_resource[] = { + { + .flags = IORESOURCE_MEM, + }, + { + .flags = IORESOURCE_IRQ, + }, + { + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device gpmc_nand_device = { .name = "omap2-nand", .id = 0, - .num_resources = 1, - .resource = &gpmc_nand_resource, + .num_resources = ARRAY_SIZE(gpmc_nand_resource), + .resource = gpmc_nand_resource, }; static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data) @@ -75,6 +83,7 @@ static int omap2_nand_gpmc_retime(struct omap_nand_platform_data *gpmc_nand_data gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_SIZE, 0); gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NAND); + gpmc_cs_configure(gpmc_nand_data->cs, GPMC_CONFIG_WP, 0); err = gpmc_cs_set_timings(gpmc_nand_data->cs, &t); if (err) return err; @@ -90,14 +99,19 @@ int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data) gpmc_nand_device.dev.platform_data = gpmc_nand_data; err = gpmc_cs_request(gpmc_nand_data->cs, NAND_IO_SIZE, - (unsigned long *)&gpmc_nand_resource.start); + (unsigned long *)&gpmc_nand_resource[0].start); if (err < 0) { dev_err(dev, "Cannot request GPMC CS\n"); return err; } - gpmc_nand_resource.end = gpmc_nand_resource.start + NAND_IO_SIZE - 1; + gpmc_nand_resource[0].end = gpmc_nand_resource[0].start + + NAND_IO_SIZE - 1; + gpmc_nand_resource[1].start = + gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE); + gpmc_nand_resource[2].start = + gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT); /* Set timings in GPMC */ err = omap2_nand_gpmc_retime(gpmc_nand_data); if (err < 0) { -- cgit v0.10.2 From 5c4684557b7e37afd42fa35f420f2f28bfb75442 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 30 Aug 2012 12:53:24 -0700 Subject: mtd: nand: omap2: use gpmc provided irqs GPMC platform initialization provides it's clients with interrupts that can be used through struct resource. Make use of it for irq mode functionality. Also now write protect disable is done by GPMC, hence remove it. Signed-off-by: Afzal Mohammed Acked-by: Artem Bityutskiy [tony@atomide.com: updated to fix new warnings introduced] Signed-off-by: Tony Lindgren diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 3578c63..27293e3 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -137,7 +137,8 @@ struct omap_nand_info { unsigned long mem_size; struct completion comp; struct dma_chan *dma; - int gpmc_irq; + int gpmc_irq_fifo; + int gpmc_irq_count; enum { OMAP_NAND_IO_READ = 0, /* read */ OMAP_NAND_IO_WRITE, /* write */ @@ -553,14 +554,12 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) { struct omap_nand_info *info = (struct omap_nand_info *) dev; u32 bytes; - u32 irq_stat; - irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS); bytes = readl(info->reg.gpmc_prefetch_status); bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(bytes); bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ - if (irq_stat & 0x2) + if (this_irq == info->gpmc_irq_count) goto done; if (info->buf_len && (info->buf_len < bytes)) @@ -577,20 +576,17 @@ static irqreturn_t omap_nand_irq(int this_irq, void *dev) (u32 *)info->buf, bytes >> 2); info->buf = info->buf + bytes; - if (irq_stat & 0x2) + if (this_irq == info->gpmc_irq_count) goto done; } - gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); return IRQ_HANDLED; done: complete(&info->comp); - /* disable irq */ - gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0); - /* clear status */ - gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); + disable_irq_nosync(info->gpmc_irq_fifo); + disable_irq_nosync(info->gpmc_irq_count); return IRQ_HANDLED; } @@ -624,9 +620,9 @@ static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) goto out_copy; info->buf_len = len; - /* enable irq */ - gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, - (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); + + enable_irq(info->gpmc_irq_count); + enable_irq(info->gpmc_irq_fifo); /* waiting for read to complete */ wait_for_completion(&info->comp); @@ -674,12 +670,13 @@ static void omap_write_buf_irq_pref(struct mtd_info *mtd, goto out_copy; info->buf_len = len; - /* enable irq */ - gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, - (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); + + enable_irq(info->gpmc_irq_count); + enable_irq(info->gpmc_irq_fifo); /* waiting for write to complete */ wait_for_completion(&info->comp); + /* wait for data to flushed-out before reset the prefetch */ tim = 0; limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); @@ -1300,9 +1297,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->nand.options = pdata->devsize; info->nand.options |= NAND_SKIP_BBTSCAN; - /* NAND write protect off */ - gpmc_cs_configure(info->gpmc_cs, GPMC_CONFIG_WP, 0); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { err = -EINVAL; @@ -1392,17 +1386,39 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) break; case NAND_OMAP_PREFETCH_IRQ: - err = request_irq(pdata->gpmc_irq, - omap_nand_irq, IRQF_SHARED, "gpmc-nand", info); + info->gpmc_irq_fifo = platform_get_irq(pdev, 0); + if (info->gpmc_irq_fifo <= 0) { + dev_err(&pdev->dev, "error getting fifo irq\n"); + err = -ENODEV; + goto out_release_mem_region; + } + err = request_irq(info->gpmc_irq_fifo, omap_nand_irq, + IRQF_SHARED, "gpmc-nand-fifo", info); if (err) { dev_err(&pdev->dev, "requesting irq(%d) error:%d", - pdata->gpmc_irq, err); + info->gpmc_irq_fifo, err); + info->gpmc_irq_fifo = 0; + goto out_release_mem_region; + } + + info->gpmc_irq_count = platform_get_irq(pdev, 1); + if (info->gpmc_irq_count <= 0) { + dev_err(&pdev->dev, "error getting count irq\n"); + err = -ENODEV; + goto out_release_mem_region; + } + err = request_irq(info->gpmc_irq_count, omap_nand_irq, + IRQF_SHARED, "gpmc-nand-count", info); + if (err) { + dev_err(&pdev->dev, "requesting irq(%d) error:%d", + info->gpmc_irq_count, err); + info->gpmc_irq_count = 0; goto out_release_mem_region; - } else { - info->gpmc_irq = pdata->gpmc_irq; - info->nand.read_buf = omap_read_buf_irq_pref; - info->nand.write_buf = omap_write_buf_irq_pref; } + + info->nand.read_buf = omap_read_buf_irq_pref; + info->nand.write_buf = omap_write_buf_irq_pref; + break; default: @@ -1490,6 +1506,10 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) out_release_mem_region: if (info->dma) dma_release_channel(info->dma); + if (info->gpmc_irq_count > 0) + free_irq(info->gpmc_irq_count, info); + if (info->gpmc_irq_fifo > 0) + free_irq(info->gpmc_irq_fifo, info); release_mem_region(info->phys_base, info->mem_size); out_free_info: kfree(info); @@ -1508,8 +1528,10 @@ static int omap_nand_remove(struct platform_device *pdev) if (info->dma) dma_release_channel(info->dma); - if (info->gpmc_irq) - free_irq(info->gpmc_irq, info); + if (info->gpmc_irq_count > 0) + free_irq(info->gpmc_irq_count, info); + if (info->gpmc_irq_fifo > 0) + free_irq(info->gpmc_irq_fifo, info); /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); -- cgit v0.10.2 From 624411ceba816b38e9e4a013c7e4c5f36a9f4cfe Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Mon, 30 Jul 2012 18:42:20 +0530 Subject: arm/dts: Cleanup regulator naming and remove @0,1 regulators do not have a 'reg' property, hence the regulator@0, regulator@1 do not make sense. get rid of it. Reported-by: David Brown Signed-off-by: Rajendra Nayak Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index cdcb98c..e60cba0 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -27,7 +27,7 @@ interrupts = <7>; /* SYS_NIRQ cascaded to intc */ interrupt-parent = <&intc>; - vsim: regulator@10 { + vsim: regulator-vsim { compatible = "ti,twl4030-vsim"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3000000>; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 72216e9..dbcdc4a 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -18,7 +18,7 @@ reg = <0x80000000 0x40000000>; /* 1 GB */ }; - vdd_eth: fixedregulator@0 { + vdd_eth: fixedregulator-vdd-eth { compatible = "regulator-fixed"; regulator-name = "VDD_ETH"; regulator-min-microvolt = <3300000>; @@ -28,7 +28,7 @@ regulator-boot-on; }; - vbat: fixedregulator@2 { + vbat: fixedregulator-vbat { compatible = "regulator-fixed"; regulator-name = "VBAT"; regulator-min-microvolt = <3750000>; diff --git a/arch/arm/boot/dts/twl4030.dtsi b/arch/arm/boot/dts/twl4030.dtsi index 22f4d13..ff00017 100644 --- a/arch/arm/boot/dts/twl4030.dtsi +++ b/arch/arm/boot/dts/twl4030.dtsi @@ -19,19 +19,19 @@ interrupts = <11>; }; - vdac: regulator@0 { + vdac: regulator-vdac { compatible = "ti,twl4030-vdac"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - vpll2: regulator@1 { + vpll2: regulator-vpll2 { compatible = "ti,twl4030-vpll2"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; - vmmc1: regulator@2 { + vmmc1: regulator-vmmc1 { compatible = "ti,twl4030-vmmc1"; regulator-min-microvolt = <1850000>; regulator-max-microvolt = <3150000>; diff --git a/arch/arm/boot/dts/twl6030.dtsi b/arch/arm/boot/dts/twl6030.dtsi index d351b27..123e2c4 100644 --- a/arch/arm/boot/dts/twl6030.dtsi +++ b/arch/arm/boot/dts/twl6030.dtsi @@ -20,70 +20,70 @@ interrupts = <11>; }; - vaux1: regulator@0 { + vaux1: regulator-vaux1 { compatible = "ti,twl6030-vaux1"; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3000000>; }; - vaux2: regulator@1 { + vaux2: regulator-vaux2 { compatible = "ti,twl6030-vaux2"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <2800000>; }; - vaux3: regulator@2 { + vaux3: regulator-vaux3 { compatible = "ti,twl6030-vaux3"; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <3000000>; }; - vmmc: regulator@3 { + vmmc: regulator-vmmc { compatible = "ti,twl6030-vmmc"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <3000000>; }; - vpp: regulator@4 { + vpp: regulator-vpp { compatible = "ti,twl6030-vpp"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2500000>; }; - vusim: regulator@5 { + vusim: regulator-vusim { compatible = "ti,twl6030-vusim"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <2900000>; }; - vdac: regulator@6 { + vdac: regulator-vdac { compatible = "ti,twl6030-vdac"; }; - vana: regulator@7 { + vana: regulator-vana { compatible = "ti,twl6030-vana"; }; - vcxio: regulator@8 { + vcxio: regulator-vcxio { compatible = "ti,twl6030-vcxio"; regulator-always-on; }; - vusb: regulator@9 { + vusb: regulator-vusb { compatible = "ti,twl6030-vusb"; }; - v1v8: regulator@10 { + v1v8: regulator-v1v8 { compatible = "ti,twl6030-v1v8"; regulator-always-on; }; - v2v1: regulator@11 { + v2v1: regulator-v2v1 { compatible = "ti,twl6030-v2v1"; regulator-always-on; }; - clk32kg: regulator@12 { + clk32kg: regulator-clk32kg { compatible = "ti,twl6030-clk32kg"; }; }; -- cgit v0.10.2 From d5d08e2e1672da627d7c9d34a9dc1089c653e23a Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Tue, 21 Aug 2012 16:47:27 +0530 Subject: arm/dts: regulator: Add tps65910 device tree data Add device tree data for tps65910 regulator by adding all tps65910 regulator nodes. Regulator is initialized based on compatiable name provided in tps65910 DT file. All tps65910 PMIC regulator device tree nodes are placed in a seperate device tree include file (tps65910.dtsi). This patch was tested on AM335x-EVM. Signed-off-by: AnilKumar Ch Reviewed-by: Mark Brown Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/tps65910.dtsi b/arch/arm/boot/dts/tps65910.dtsi new file mode 100644 index 0000000..92693a8 --- /dev/null +++ b/arch/arm/boot/dts/tps65910.dtsi @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Integrated Power Management Chip + * http://www.ti.com/lit/ds/symlink/tps65910.pdf + */ + +&tps { + compatible = "ti,tps65910"; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + vrtc_reg: regulator@0 { + reg = <0>; + regulator-compatible = "vrtc"; + }; + + vio_reg: regulator@1 { + reg = <1>; + regulator-compatible = "vio"; + }; + + vdd1_reg: regulator@2 { + reg = <2>; + regulator-compatible = "vdd1"; + }; + + vdd2_reg: regulator@3 { + reg = <3>; + regulator-compatible = "vdd2"; + }; + + vdd3_reg: regulator@4 { + reg = <4>; + regulator-compatible = "vdd3"; + }; + + vdig1_reg: regulator@5 { + reg = <5>; + regulator-compatible = "vdig1"; + }; + + vdig2_reg: regulator@6 { + reg = <6>; + regulator-compatible = "vdig2"; + }; + + vpll_reg: regulator@7 { + reg = <7>; + regulator-compatible = "vpll"; + }; + + vdac_reg: regulator@8 { + reg = <8>; + regulator-compatible = "vdac"; + }; + + vaux1_reg: regulator@9 { + reg = <9>; + regulator-compatible = "vaux1"; + }; + + vaux2_reg: regulator@10 { + reg = <10>; + regulator-compatible = "vaux2"; + }; + + vaux33_reg: regulator@11 { + reg = <11>; + regulator-compatible = "vaux33"; + }; + + vmmc_reg: regulator@12 { + reg = <12>; + regulator-compatible = "vmmc"; + }; + }; +}; -- cgit v0.10.2 From 54a37bae248d5b9e1d1057c4f8b4f8af8d6e5456 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Tue, 21 Aug 2012 16:47:28 +0530 Subject: arm/dts: regulator: Add tps65217 device tree data Add device tree data for tps65217 regulator by adding all tps65217 regulator nodes. Regulator is initialized based on compatiable name provided in tps65217 DT file. All tps65910 PMIC regulator device tree nodes are placed in a seperate device tree include file (tps65217.dtsi). This patch was tested on AM335x-Bone. Signed-off-by: AnilKumar Ch Reviewed-by: Mark Brown Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/tps65217.dtsi b/arch/arm/boot/dts/tps65217.dtsi new file mode 100644 index 0000000..a632724 --- /dev/null +++ b/arch/arm/boot/dts/tps65217.dtsi @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Integrated Power Management Chip + * http://www.ti.com/lit/ds/symlink/tps65217.pdf + */ + +&tps { + compatible = "ti,tps65217"; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + dcdc1_reg: regulator@0 { + reg = <0>; + regulator-compatible = "dcdc1"; + }; + + dcdc2_reg: regulator@1 { + reg = <1>; + regulator-compatible = "dcdc2"; + }; + + dcdc3_reg: regulator@2 { + reg = <2>; + regulator-compatible = "dcdc3"; + }; + + ldo1_reg: regulator@3 { + reg = <3>; + regulator-compatible = "ldo1"; + }; + + ldo2_reg: regulator@4 { + reg = <4>; + regulator-compatible = "ldo2"; + }; + + ldo3_reg: regulator@5 { + reg = <5>; + regulator-compatible = "ldo3"; + }; + + ldo4_reg: regulator@6 { + reg = <6>; + regulator-compatible = "ldo4"; + }; + }; +}; -- cgit v0.10.2 From 1b2a9702b0f5f377ceacdbd3b2cfdf863ef53bbc Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Tue, 21 Aug 2012 16:47:29 +0530 Subject: arm/dts: Add tps65910 regulator DT data to am335x-evm.dts Add tps65910 regulator device tree data to AM335x-EVM by adding regulator consumers with tightened constraints and regulator-name. TPS65910 regulator handle can be obtained by using this regulator name. This patch also add I2C node with I2C frequency and tps65910 PMIC I2C slave address. Signed-off-by: AnilKumar Ch Reviewed-by: Mark Brown Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 5dd8a6b..9fcbacd 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -22,5 +22,99 @@ uart1: serial@44E09000 { status = "okay"; }; + + i2c1: i2c@44E0B000 { + status = "okay"; + clock-frequency = <400000>; + + tps: tps@2D { + reg = <0x2D>; + }; + }; + }; + + vbat: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "vbat"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; +}; + +/include/ "tps65910.dtsi" + +&tps { + vcc1-supply = <&vbat>; + vcc2-supply = <&vbat>; + vcc3-supply = <&vbat>; + vcc4-supply = <&vbat>; + vcc5-supply = <&vbat>; + vcc6-supply = <&vbat>; + vcc7-supply = <&vbat>; + vccio-supply = <&vbat>; + + regulators { + vrtc_reg: regulator@0 { + regulator-always-on; + }; + + vio_reg: regulator@1 { + regulator-always-on; + }; + + vdd1_reg: regulator@2 { + /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */ + regulator-name = "vdd_mpu"; + regulator-min-microvolt = <912500>; + regulator-max-microvolt = <1312500>; + regulator-boot-on; + regulator-always-on; + }; + + vdd2_reg: regulator@3 { + /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */ + regulator-name = "vdd_core"; + regulator-min-microvolt = <912500>; + regulator-max-microvolt = <1150000>; + regulator-boot-on; + regulator-always-on; + }; + + vdd3_reg: regulator@4 { + regulator-always-on; + }; + + vdig1_reg: regulator@5 { + regulator-always-on; + }; + + vdig2_reg: regulator@6 { + regulator-always-on; + }; + + vpll_reg: regulator@7 { + regulator-always-on; + }; + + vdac_reg: regulator@8 { + regulator-always-on; + }; + + vaux1_reg: regulator@9 { + regulator-always-on; + }; + + vaux2_reg: regulator@10 { + regulator-always-on; + }; + + vaux33_reg: regulator@11 { + regulator-always-on; + }; + + vmmc_reg: regulator@12 { + regulator-always-on; + }; }; }; -- cgit v0.10.2 From a06ceff6f29e34edff5d6b082885c1c4139a0362 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Tue, 21 Aug 2012 16:47:30 +0530 Subject: arm/dts: Add tps65217 regulator DT data to am335x-bone.dts Add tps65217 regulator device tree data to AM335x-Bone by adding regulator consumers with tightened constraints and regulator-name. TPS65217 regulator handle can be obtained by using this regulator name. This patch also add I2C node with I2C frequency and tps65217 PMIC I2C slave address. Signed-off-by: AnilKumar Ch Reviewed-by: Mark Brown Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts index a7906cb..917e784 100644 --- a/arch/arm/boot/dts/am335x-bone.dts +++ b/arch/arm/boot/dts/am335x-bone.dts @@ -22,5 +22,59 @@ uart1: serial@44E09000 { status = "okay"; }; + + i2c1: i2c@44E0B000 { + status = "okay"; + clock-frequency = <400000>; + + tps: tps@24 { + reg = <0x24>; + }; + + }; + }; +}; + +/include/ "tps65217.dtsi" + +&tps { + regulators { + dcdc1_reg: regulator@0 { + regulator-always-on; + }; + + dcdc2_reg: regulator@1 { + /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */ + regulator-name = "vdd_mpu"; + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <1325000>; + regulator-boot-on; + regulator-always-on; + }; + + dcdc3_reg: regulator@2 { + /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */ + regulator-name = "vdd_core"; + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <1150000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1_reg: regulator@3 { + regulator-always-on; + }; + + ldo2_reg: regulator@4 { + regulator-always-on; + }; + + ldo3_reg: regulator@5 { + regulator-always-on; + }; + + ldo4_reg: regulator@6 { + regulator-always-on; + }; }; }; -- cgit v0.10.2 From ee3c843d0fc21c68ced93b982b5731178a24df68 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 8 Aug 2012 23:03:07 -0700 Subject: ARM: shmobile: armadillo800eva: fixup: sound card detection order Since armadillo800eva has 2 sound cards, and had reversed deferred probe order issue, it was purposely registered in reverse order. But it was solved by 1d29cfa57471a5e4b8a7c2a7433eeba170d3ad92 (driver core: fixup reversed deferred probe order) armadillo800eva board is expecting that FSI-WM8978 is the 1st, and FSI-HDMI is the 2nd sound card. This patch fixes it up Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index cf10f92..ecd8136 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -901,8 +901,8 @@ static struct platform_device *eva_devices[] __initdata = { &camera_device, &ceu0_device, &fsi_device, - &fsi_hdmi_device, &fsi_wm8978_device, + &fsi_hdmi_device, }; static void __init eva_clock_init(void) -- cgit v0.10.2 From e26a6038d3a902cd0bc784fc55571a83d7f9cb79 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 5 Aug 2012 22:47:00 -0700 Subject: ARM: shmobile: mackerel: fixup usb module order renesas_usbhs driver can play role as both Host and Gadget. In case of Gadget, it requires not only renesas_usbhs but also usb gadget module (like g_ether). So, renesas_usbhs driver calls usb_add_gadget_udc() on probe time. Because of this behavior, Host port plays also Gadget role if kernel has both Host/Gadget support. In mackerel case, from 0ada2da51800a4914887a9bcf22d563be80e50be (ARM: mach-shmobile: mackerel: use renesas_usbhs instead of r8a66597_hcd) usb0 plays Gadget role, and usb1 plays Host role, and current mackerel board probes as usb1 -> usb0. Thus, 1st installed usb gadget module (like g_ether) will be assigned to usb1 (= usb Host port), and 2nd module to usb0 (= usb Gadget port). It is very confusable for user. This patch fixup usb modes probing order as usb0 -> usb1. Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 7ea2b31..c129542 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -695,6 +695,7 @@ static struct platform_device usbhs0_device = { * - J30 "open" * - modify usbhs1_get_id() USBHS_HOST -> USBHS_GADGET * - add .get_vbus = usbhs_get_vbus in usbhs1_private + * - check usbhs0_device(pio)/usbhs1_device(irq) order in mackerel_devices. */ #define IRQ8 evt2irq(0x0300) #define USB_PHY_MODE (1 << 4) @@ -1325,8 +1326,8 @@ static struct platform_device *mackerel_devices[] __initdata = { &nor_flash_device, &smc911x_device, &lcdc_device, - &usbhs1_device, &usbhs0_device, + &usbhs1_device, &leds_device, &fsi_device, &fsi_ak4643_device, -- cgit v0.10.2 From 5b423f6a40a0327f9d40bc8b97ce9be266f74368 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 29 Aug 2012 16:25:49 +0000 Subject: netfilter: nf_conntrack: fix racy timer handling with reliable events Existing code assumes that del_timer returns true for alive conntrack entries. However, this is not true if reliable events are enabled. In that case, del_timer may return true for entries that were just inserted in the dying list. Note that packets / ctnetlink may hold references to conntrack entries that were just inserted to such list. This patch fixes the issue by adding an independent timer for event delivery. This increases the size of the ecache extension. Still we can revisit this later and use variable size extensions to allocate this area on demand. Tested-by: Oliver Smith Signed-off-by: Pablo Neira Ayuso diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index e1ce104..4a045cd 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -18,6 +18,7 @@ struct nf_conntrack_ecache { u16 ctmask; /* bitmask of ct events to be delivered */ u16 expmask; /* bitmask of expect events to be delivered */ u32 pid; /* netlink pid of destroyer */ + struct timer_list timeout; }; static inline struct nf_conntrack_ecache * diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index cf48755..2ceec64 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -249,12 +249,15 @@ static void death_by_event(unsigned long ul_conntrack) { struct nf_conn *ct = (void *)ul_conntrack; struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); + + BUG_ON(ecache == NULL); if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) { /* bad luck, let's retry again */ - ct->timeout.expires = jiffies + + ecache->timeout.expires = jiffies + (random32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ct->timeout); + add_timer(&ecache->timeout); return; } /* we've got the event delivered, now it's dying */ @@ -268,6 +271,9 @@ static void death_by_event(unsigned long ul_conntrack) void nf_ct_insert_dying_list(struct nf_conn *ct) { struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct); + + BUG_ON(ecache == NULL); /* add this conntrack to the dying list */ spin_lock_bh(&nf_conntrack_lock); @@ -275,10 +281,10 @@ void nf_ct_insert_dying_list(struct nf_conn *ct) &net->ct.dying); spin_unlock_bh(&nf_conntrack_lock); /* set a new timer to retry event delivery */ - setup_timer(&ct->timeout, death_by_event, (unsigned long)ct); - ct->timeout.expires = jiffies + + setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct); + ecache->timeout.expires = jiffies + (random32() % net->ct.sysctl_events_retry_timeout); - add_timer(&ct->timeout); + add_timer(&ecache->timeout); } EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); -- cgit v0.10.2 From 4fd20570995c46b08711b062c69ab903319d6041 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 30 Aug 2012 07:39:12 +0200 Subject: ARM: Kirkwood: Fix 'SZ_1M' undeclared here for db88f6281-bp-setup.c Linux-next has failed to compile for kirkwood since 23 August with: arch/arm/mach-kirkwood/db88f6281-bp-setup.c:29: error: 'SZ_1M' undeclared here (not in a function) arch/arm/mach-kirkwood/db88f6281-bp-setup.c:33: error: 'SZ_4M' undeclared here (not in a function) Add missing Signed-off-by: Andrew Lunn Signed-off-by: Jason Cooper diff --git a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c index d933593..be90b7d 100644 --- a/arch/arm/mach-kirkwood/db88f6281-bp-setup.c +++ b/arch/arm/mach-kirkwood/db88f6281-bp-setup.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include -- cgit v0.10.2 From 03d2f44e967b3c2cf79a6dfb904c8880616c7f83 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Thu, 30 Aug 2012 17:11:17 -0400 Subject: ALSA: snd-usb: use list_for_each_safe for endpoint resources snd_usb_endpoint_free() frees the structure that contains its argument. Signed-off-by: Pavel Roskin Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai diff --git a/sound/usb/card.c b/sound/usb/card.c index d5b5c33..4a469f0 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -553,7 +553,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, struct snd_usb_audio *chip) { struct snd_card *card; - struct list_head *p; + struct list_head *p, *n; if (chip == (void *)-1L) return; @@ -570,7 +570,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, snd_usb_stream_disconnect(p); } /* release the endpoint resources */ - list_for_each(p, &chip->ep_list) { + list_for_each_safe(p, n, &chip->ep_list) { snd_usb_endpoint_free(p); } /* release the midi resources */ -- cgit v0.10.2 From fbcfbf5f673847657ccd98afb4d8e13af7fdc372 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 30 Aug 2012 18:52:29 +0200 Subject: ALSA: snd-usb: restore delay information Parts of commit 294c4fb8 ("ALSA: usb: refine delay information with USB frame counter") were unfortunately lost during the refactoring of the snd-usb driver in 3.5. This patch adds them back, restoring the correct delay information behaviour. Signed-off-by: Daniel Mack Cc: Pierre-Louis Bossart Cc: stable@kernel.org [3.5+] Signed-off-by: Takashi Iwai diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 1546577..5ceb8f1 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1091,7 +1091,16 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, subs->hwptr_done += bytes; if (subs->hwptr_done >= runtime->buffer_size * stride) subs->hwptr_done -= runtime->buffer_size * stride; + + /* update delay with exact number of samples queued */ + runtime->delay = subs->last_delay; runtime->delay += frames; + subs->last_delay = runtime->delay; + + /* realign last_frame_number */ + subs->last_frame_number = usb_get_current_frame_number(subs->dev); + subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ + spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = bytes; if (period_elapsed) @@ -1109,12 +1118,26 @@ static void retire_playback_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; int stride = runtime->frame_bits >> 3; int processed = urb->transfer_buffer_length / stride; + int est_delay; spin_lock_irqsave(&subs->lock, flags); - if (processed > runtime->delay) - runtime->delay = 0; + est_delay = snd_usb_pcm_delay(subs, runtime->rate); + /* update delay with exact number of samples played */ + if (processed > subs->last_delay) + subs->last_delay = 0; else - runtime->delay -= processed; + subs->last_delay -= processed; + runtime->delay = subs->last_delay; + + /* + * Report when delay estimate is off by more than 2ms. + * The error should be lower than 2ms since the estimate relies + * on two reads of a counter updated every ms. + */ + if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) + snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", + est_delay, subs->last_delay); + spin_unlock_irqrestore(&subs->lock, flags); } -- cgit v0.10.2 From 245baf983cc39524cce39c24d01b276e6e653c9e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 30 Aug 2012 18:52:30 +0200 Subject: ALSA: snd-usb: fix calls to next_packet_size In order to support devices with implicit feedback streaming models, packet sizes are now stored with each individual urb, and the PCM handling code which fills the buffers purely relies on the size fields now. However, calling snd_usb_audio_next_packet_size() for all possible packets in an URB at once, prior to letting the PCM code do its job does in fact not lead to the same behaviour than what the old code did: The PCM code will break its loop once a period boundary is reached, consequently using up less packets that it really could. As snd_usb_audio_next_packet_size() implements a feedback mechanism to the endpoints phase accumulator, the number of calls to that function matters, and when called too often, the data rate runs out of bounds. Fix this by making the next_packet function public, and call it from the PCM code as before if the packet data sizes are not defined. Signed-off-by: Daniel Mack Cc: stable@kernel.org [v3.5+] Signed-off-by: Takashi Iwai diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index b896c55..d6e2bb4 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -141,7 +141,7 @@ int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep) * * For implicit feedback, next_packet_size() is unused. */ -static int next_packet_size(struct snd_usb_endpoint *ep) +int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) { unsigned long flags; int ret; @@ -177,15 +177,6 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep, ep->retire_data_urb(ep->data_subs, urb); } -static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *ctx) -{ - int i; - - for (i = 0; i < ctx->packets; ++i) - ctx->packet_size[i] = next_packet_size(ep); -} - /* * Prepare a PLAYBACK urb for submission to the bus. */ @@ -370,7 +361,6 @@ static void snd_complete_urb(struct urb *urb) goto exit_clear; } - prepare_outbound_urb_sizes(ep, ctx); prepare_outbound_urb(ep, ctx); } else { retire_inbound_urb(ep, ctx); @@ -857,7 +847,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep) goto __error; if (usb_pipeout(ep->pipe)) { - prepare_outbound_urb_sizes(ep, urb->context); prepare_outbound_urb(ep, urb->context); } else { prepare_inbound_urb(ep, urb->context); diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index a8e60c1..cbbbdf2 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -21,6 +21,7 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); void snd_usb_endpoint_free(struct list_head *head); int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep); +int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep); void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, struct snd_usb_endpoint *sender, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 5ceb8f1..e80b668 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1029,6 +1029,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, struct urb *urb) { struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; + struct snd_usb_endpoint *ep = subs->data_endpoint; struct snd_urb_ctx *ctx = urb->context; unsigned int counts, frames, bytes; int i, stride, period_elapsed = 0; @@ -1040,7 +1041,11 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, urb->number_of_packets = 0; spin_lock_irqsave(&subs->lock, flags); for (i = 0; i < ctx->packets; i++) { - counts = ctx->packet_size[i]; + if (ctx->packet_size[i]) + counts = ctx->packet_size[i]; + else + counts = snd_usb_endpoint_next_packet_size(ep); + /* set up descriptor */ urb->iso_frame_desc[i].offset = frames * stride; urb->iso_frame_desc[i].length = counts * stride; -- cgit v0.10.2 From 2e4a263ca80a203ac6109f5932722a716c265395 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 30 Aug 2012 18:52:31 +0200 Subject: ALSA: snd-usb: fix cross-interface streaming devices Commit 68e67f40b ("ALSA: snd-usb: move calls to usb_set_interface") saved us some unnecessary calls to snd_usb_set_interface() but ignored the fact that there is at least one device out there which operates on two endpoint in different interfaces simultaniously. Take care for this by catching the case where data and sync endpoints are located on different interfaces and calling snd_usb_set_interface() between the start of the two endpoints. Signed-off-by: Daniel Mack Reported-by: Robert M. Albrecht Cc: stable@kernel.org [v3.5+] Signed-off-by: Takashi Iwai diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index e80b668..fd5e982 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -236,6 +236,21 @@ static int start_endpoints(struct snd_usb_substream *subs, int can_sleep) !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { struct snd_usb_endpoint *ep = subs->sync_endpoint; + if (subs->data_endpoint->iface != subs->sync_endpoint->iface || + subs->data_endpoint->alt_idx != subs->sync_endpoint->alt_idx) { + err = usb_set_interface(subs->dev, + subs->sync_endpoint->iface, + subs->sync_endpoint->alt_idx); + if (err < 0) { + snd_printk(KERN_ERR + "%d:%d:%d: cannot set interface (%d)\n", + subs->dev->devnum, + subs->sync_endpoint->iface, + subs->sync_endpoint->alt_idx, err); + return -EIO; + } + } + snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep); ep->sync_slave = subs->data_endpoint; -- cgit v0.10.2 From b72c200975a4ed579dbf3353019e19528745a29a Mon Sep 17 00:00:00 2001 From: Jaccon Bastiaansen Date: Mon, 27 Aug 2012 11:53:51 +0000 Subject: cs89x0 : packet reception not working The RxCFG register of the CS89x0 could be configured incorrectly (because of misplaced parentheses), resulting in the disabling of packet reception. Signed-off-by: Jaccon Bastiaansen Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c index 845b202..1384469 100644 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ b/drivers/net/ethernet/cirrus/cs89x0.c @@ -1243,6 +1243,7 @@ static void set_multicast_list(struct net_device *dev) { struct net_local *lp = netdev_priv(dev); unsigned long flags; + u16 cfg; spin_lock_irqsave(&lp->lock, flags); if (dev->flags & IFF_PROMISC) @@ -1260,11 +1261,10 @@ static void set_multicast_list(struct net_device *dev) /* in promiscuous mode, we accept errored packets, * so we have to enable interrupts on them also */ - writereg(dev, PP_RxCFG, - (lp->curr_rx_cfg | - (lp->rx_mode == RX_ALL_ACCEPT) - ? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL) - : 0)); + cfg = lp->curr_rx_cfg; + if (lp->rx_mode == RX_ALL_ACCEPT) + cfg |= RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL; + writereg(dev, PP_RxCFG, cfg); spin_unlock_irqrestore(&lp->lock, flags); } -- cgit v0.10.2 From ab6f148de28261682d300662e87b9477f7efc95b Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sun, 26 Aug 2012 20:41:38 +0000 Subject: usbnet: fix deadlock in resume A usbnet device can share a multifunction device with a storage device. If the storage device is autoresumed the usbnet devices also needs to be autoresumed. Allocating memory with GFP_KERNEL can deadlock in this case. This should go back into all kernels that have commit 65841fd5132c3941cdf5df09e70df3ed28323212 That is 3.5 Signed-off-by: Oliver Neukum CC: stable@kernel.org Signed-off-by: David S. Miller diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 8531c1c..fd4b26d 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1573,7 +1573,7 @@ int usbnet_resume (struct usb_interface *intf) netif_device_present(dev->net) && !timer_pending(&dev->delay) && !test_bit(EVENT_RX_HALT, &dev->flags)) - rx_alloc_submit(dev, GFP_KERNEL); + rx_alloc_submit(dev, GFP_NOIO); if (!(dev->txq.qlen >= TX_QLEN(dev))) netif_tx_wake_all_queues(dev->net); -- cgit v0.10.2 From fa026e223df2514b271b20f839ab05d7f21181b9 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Tue, 28 Aug 2012 02:30:32 +0000 Subject: net: qmi_wwan: new device: Foxconn/Novatel E396 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Foxconn-branded Novatel E396, Gobi3k modem. Cc: Dan Williams Cc: Bjørn Mork Cc: Ben Chan Signed-off-by: Aleksander Morgado Acked-by: Bjørn Mork Signed-off-by: David S. Miller diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 328397c..189e52d 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -441,6 +441,7 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ + {QMI_GOBI_DEVICE(0x1410, 0xa021)}, /* Foxconn Gobi 3000 Modem device (Novatel E396) */ { } /* END */ }; -- cgit v0.10.2 From 48f125ce1cc3ff275f9587b5bf56bf0f90766c7d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 29 Aug 2012 06:49:12 +0000 Subject: net: ipv6: fix error return code Initialize return variable before exiting on an error path. The initial initialization of the return variable is also dropped, because that value is never used. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 6dc7fd3..282f372 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -167,8 +167,6 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) struct esp_data *esp = x->data; /* skb is pure payload to encrypt */ - err = -ENOMEM; - aead = esp->aead; alen = crypto_aead_authsize(aead); @@ -203,8 +201,10 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) } tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); - if (!tmp) + if (!tmp) { + err = -ENOMEM; goto error; + } seqhi = esp_tmp_seqhi(tmp); iv = esp_tmp_iv(aead, tmp, seqhilen); -- cgit v0.10.2 From 599901c3e4204e9d9c5a24df5402cd91617a2a26 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 29 Aug 2012 06:49:15 +0000 Subject: net/xfrm/xfrm_state.c: fix error return code Initialize return variable before exiting on an error path. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 87cd0e4..210be48 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1994,8 +1994,10 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay) goto error; x->outer_mode = xfrm_get_mode(x->props.mode, family); - if (x->outer_mode == NULL) + if (x->outer_mode == NULL) { + err = -EPROTONOSUPPORT; goto error; + } if (init_replay) { err = xfrm_init_replay(x); -- cgit v0.10.2 From b27393aecf66199f5ddad37c302d3e0cfadbe6c0 Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Thu, 30 Aug 2012 06:37:32 +0000 Subject: net: ethernet: fix kernel OOPS when remove davinci_mdio module davinci mdio device is not unregistered from mdiobus when removing the module, which causes BUG_ON() when free the device from mdiobus. Calling mdiobus_unregister() before mdiobus_free() fixes the issue. Signed-off-by: Bin Liu Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index cd7ee20..a9ca4a0 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -394,8 +394,10 @@ static int __devexit davinci_mdio_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct davinci_mdio_data *data = dev_get_drvdata(dev); - if (data->bus) + if (data->bus) { + mdiobus_unregister(data->bus); mdiobus_free(data->bus); + } if (data->clk) clk_put(data->clk); -- cgit v0.10.2 From 4c30aa33d4b4ce9a0ee5b32d058a40f4eca2ab63 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 29 Aug 2012 09:35:24 +0800 Subject: gpio: mc9s08dz60: Fix build error if I2C=m Make GPIO_MC9S08DZ60 depend on I2C=y, this fixes below build error: LD init/built-in.o drivers/built-in.o: In function `mc9s08dz60_get_value': clk-fixed-factor.c:(.text+0x7214): undefined reference to `i2c_smbus_read_byte_data' drivers/built-in.o: In function `mc9s08dz60_set': clk-fixed-factor.c:(.text+0x727c): undefined reference to `i2c_smbus_read_byte_data' clk-fixed-factor.c:(.text+0x72bc): undefined reference to `i2c_smbus_write_byte_data' drivers/built-in.o: In function `mc9s08dz60_i2c_driver_init': clk-fixed-factor.c:(.init.text+0x290): undefined reference to `i2c_register_driver' drivers/built-in.o: In function `mc9s08dz60_i2c_driver_exit': clk-fixed-factor.c:(.exit.text+0x2c): undefined reference to `i2c_del_driver' make: *** [vmlinux] Error 1 Signed-off-by: Axel Lin Signed-off-by: Linus Walleij diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b16c8a7..ba7926f5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -294,7 +294,7 @@ config GPIO_MAX732X_IRQ config GPIO_MC9S08DZ60 bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions" - depends on I2C && MACH_MX35_3DS + depends on I2C=y && MACH_MX35_3DS help Select this to enable the MC9S08DZ60 GPIO driver -- cgit v0.10.2 From dd2914972e5f6d9c1a687158c0f65b81d239fe37 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 28 Aug 2012 19:30:44 +0800 Subject: gpio: em: Fix checking return value of irq_alloc_descs irq_alloc_descs() returns negative error code on failure. Signed-off-by: Axel Lin Acked-by: Magnus Damm Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index ae37181..ec48ed5 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -247,9 +247,9 @@ static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p) p->irq_base = irq_alloc_descs(pdata->irq_base, 0, pdata->number_of_pins, numa_node_id()); - if (IS_ERR_VALUE(p->irq_base)) { + if (p->irq_base < 0) { dev_err(&pdev->dev, "cannot get irq_desc\n"); - return -ENXIO; + return p->irq_base; } pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n", pdata->gpio_base, pdata->number_of_pins, p->irq_base); -- cgit v0.10.2 From 1146f8822ae6601e24f9072d6cd74f76506142cd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 1 Sep 2012 14:11:22 +0800 Subject: gpio: rdc321x: Prevent removal of modules exporting active GPIOs This driver can be built as a module, set the missing owner field of struct gpio_chip to prevent removal of modules exporting active GPIOs. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index e97016a..b62d443 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -170,6 +170,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) rdc321x_gpio_dev->reg2_data_base = r->start + 0x4; rdc321x_gpio_dev->chip.label = "rdc321x-gpio"; + rdc321x_gpio_dev->chip.owner = THIS_MODULE; rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input; rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config; rdc321x_gpio_dev->chip.get = rdc_gpio_get_value; -- cgit v0.10.2 From b6d86d3d6d6e4c9b588d81615c81b5a8292b62ed Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 24 Aug 2012 17:25:01 -0700 Subject: linux/kernel.h: Fix DIV_ROUND_CLOSEST to support negative dividends DIV_ROUND_CLOSEST returns a bad result for negative dividends: DIV_ROUND_CLOSEST(-2, 2) = 0 Most of the time this does not matter. However, in the hardware monitoring subsystem, DIV_ROUND_CLOSEST is sometimes used on integers which can be negative (such as temperatures). Signed-off-by: Guenter Roeck Acked-by: Jean Delvare diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 6043821..594b419 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -82,10 +82,18 @@ __x - (__x % (y)); \ } \ ) + +/* + * Divide positive or negative dividend by positive divisor and round + * to closest integer. Result is undefined for negative divisors. + */ #define DIV_ROUND_CLOSEST(x, divisor)( \ { \ - typeof(divisor) __divisor = divisor; \ - (((x) + ((__divisor) / 2)) / (__divisor)); \ + typeof(x) __x = x; \ + typeof(divisor) __d = divisor; \ + (((typeof(x))-1) >= 0 || (__x) >= 0) ? \ + (((__x) + ((__d) / 2)) / (__d)) : \ + (((__x) - ((__d) / 2)) / (__d)); \ } \ ) -- cgit v0.10.2 From e1b2aa7f3051e268973b6126fdca602ac4af6bc4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 1 Sep 2012 09:57:40 +0000 Subject: fddi: 64 bit bug in smt_add_para() The intent was to set 4 bytes of data so that's why the sp_len is set to 4 on the next line. The cast to u_long pointer clears 8 bytes on 64 bit arches. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller diff --git a/drivers/net/fddi/skfp/pmf.c b/drivers/net/fddi/skfp/pmf.c index 24d8566..441b4dc 100644 --- a/drivers/net/fddi/skfp/pmf.c +++ b/drivers/net/fddi/skfp/pmf.c @@ -673,7 +673,7 @@ void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para, sm_pm_get_ls(smc,port_to_mib(smc,port))) ; break ; case SMT_P_REASON : - * (u_long *) to = 0 ; + *(u32 *)to = 0 ; sp_len = 4 ; goto sp_done ; case SMT_P1033 : /* time stamp */ -- cgit v0.10.2 From 5002200599429e83fc13e0d9a2d4788b79515b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sat, 1 Sep 2012 03:47:26 +0000 Subject: net: qmi_wwan: add several new Gobi devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gobi devices are composite, needing both the qcserial and qmi_wwan drivers to support all functions. Re-syncing the list of supported devices with qcserial. Cc: Aleksander Morgado Cc: Thomas Tuttle Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 189e52d..adfab3f 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -413,7 +413,9 @@ static const struct usb_device_id products[] = { /* 5. Gobi 2000 and 3000 devices */ {QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ + {QMI_GOBI_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ {QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ + {QMI_GOBI_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */ {QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ {QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */ {QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */ @@ -441,6 +443,7 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ + {QMI_GOBI_DEVICE(0x12d1, 0x14f1)}, /* Sony Gobi 3000 Composite */ {QMI_GOBI_DEVICE(0x1410, 0xa021)}, /* Foxconn Gobi 3000 Modem device (Novatel E396) */ { } /* END */ -- cgit v0.10.2 From 9bfc8da00b1e74f55a52cc06a0d364f1f7f61ed8 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 1 Sep 2012 21:47:11 +0200 Subject: HID: Only dump input if someone is listening Going through the motions of printing the debug message information takes a long time; using the keyboard can lead to a 160 us irqsoff latency. This patch skips hid_dump_input() when there are no open handles, which brings latency down to 100 us. Signed-off-by: Henrik Rydberg Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8bf8a64..b8485a0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -996,7 +996,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_driver *hdrv = hid->driver; int ret; - hid_dump_input(hid, usage, value); + if (!list_empty(&hid->debug_list)) + hid_dump_input(hid, usage, value); if (hdrv && hdrv->event && hid_match_usage(hid, usage)) { ret = hdrv->event(hid, field, usage, value); -- cgit v0.10.2 From 28e515878f8896b33c325ff9767cb0237210fb4c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Sun, 2 Sep 2012 23:06:52 -0700 Subject: ARM: shmobile: armadillo800eva: enable rw rootfs mount armadillo800eva default boot loader is "hermit", and it's tag->u.core.flags has flag when kernel boots. Because of this, ${LINUX}/arch/arm/kernel/setup.c :: parse_tag_core() didn't remove MS_RDONLY flag from root_mountflags. Thus, the rootfs is mounted as "readonly". This patch adds "rw" kernel parameter, and enable read/write mounts for rootfs Cc: Masahiro Nakai Signed-off-by: Kuninori Morimoto Signed-off-by: Simon Horman diff --git a/arch/arm/configs/armadillo800eva_defconfig b/arch/arm/configs/armadillo800eva_defconfig index 7d87184..90610c7 100644 --- a/arch/arm/configs/armadillo800eva_defconfig +++ b/arch/arm/configs/armadillo800eva_defconfig @@ -33,7 +33,7 @@ CONFIG_AEABI=y CONFIG_FORCE_MAX_ZONEORDER=13 CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096" +CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096 rw" CONFIG_CMDLINE_FORCE=y CONFIG_KEXEC=y CONFIG_VFP=y -- cgit v0.10.2 From 78b495c39add820ab66ab897af9bd77a5f2e91f6 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Mon, 3 Sep 2012 17:12:29 +0300 Subject: UBI: fix a horrible memory deallocation bug UBI was mistakingly using 'kfree()' instead of 'kmem_cache_free()' when freeing "attach eraseblock" structures in vtbl.c. Thankfully, this happened only when we were doing auto-format, so many systems were unaffected. However, there are still many users affected. It is strange, but the system did not crash and nothing bad happened when the SLUB memory allocator was used. However, in case of SLOB we observed an crash right away. This problem was introduced in 2.6.39 by commit "6c1e875 UBI: add slab cache for ubi_scan_leb objects" A note for stable trees: Because variable were renamed, this won't cleanly apply to older kernels. Changing names like this should help: 1. ai -> si 2. aeb_slab_cache -> seb_slab_cache 3. new_aeb -> new_seb Reported-by: Richard Genoud Tested-by: Richard Genoud Tested-by: Artem Bityutskiy Cc: stable@vger.kernel.org [v2.6.39+] Signed-off-by: Artem Bityutskiy diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 437bc19..568307c 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -340,7 +340,7 @@ retry: * of this LEB as it will be deleted and freed in 'ubi_add_to_av()'. */ err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, vid_hdr, 0); - kfree(new_aeb); + kmem_cache_free(ai->aeb_slab_cache, new_aeb); ubi_free_vid_hdr(ubi, vid_hdr); return err; @@ -353,7 +353,7 @@ write_error: list_add(&new_aeb->u.list, &ai->erase); goto retry; } - kfree(new_aeb); + kmem_cache_free(ai->aeb_slab_cache, new_aeb); out_free: ubi_free_vid_hdr(ubi, vid_hdr); return err; -- cgit v0.10.2 From 660d9a9c4f623eeec80cec3705ae872bd5cb556d Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Mon, 30 Jul 2012 15:03:02 +0800 Subject: mmc: bfin_sdh: fix dma_desc_array build error Descriptor array structure has been moved into blackfin dma.h head file. This patch fix below error: drivers/mmc/host/bfin_sdh.c:52:8: error: redefinition of 'struct dma_desc_array' make[4]: *** [drivers/mmc/host/bfin_sdh.o] Error 1 Signed-off-by: Sonic Zhang Signed-off-by: Bob Liu Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index 0366617..a17dd73 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -49,13 +49,6 @@ #define bfin_write_SDH_CFG bfin_write_RSI_CFG #endif -struct dma_desc_array { - unsigned long start_addr; - unsigned short cfg; - unsigned short x_count; - short x_modify; -} __packed; - struct sdh_host { struct mmc_host *mmc; spinlock_t lock; -- cgit v0.10.2 From 1af36b2a993dddfa3d6860ec4879c9e8abc9b976 Mon Sep 17 00:00:00 2001 From: Lauri Hintsala Date: Tue, 17 Jul 2012 17:16:09 +0300 Subject: mmc: mxs-mmc: fix deadlock in SDIO IRQ case Release the lock before mmc_signal_sdio_irq is called by mxs_mmc_irq_handler. Backtrace: [ 79.660000] ============================================= [ 79.660000] [ INFO: possible recursive locking detected ] [ 79.660000] 3.4.0-00009-g3e96082-dirty #11 Not tainted [ 79.660000] --------------------------------------------- [ 79.660000] swapper/0 is trying to acquire lock: [ 79.660000] (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_enable_sdio_irq+0x18/0xd4 [ 79.660000] [ 79.660000] but task is already holding lock: [ 79.660000] (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_irq_handler+0x1c/0xe8 [ 79.660000] [ 79.660000] other info that might help us debug this: [ 79.660000] Possible unsafe locking scenario: [ 79.660000] [ 79.660000] CPU0 [ 79.660000] ---- [ 79.660000] lock(&(&host->lock)->rlock#2); [ 79.660000] lock(&(&host->lock)->rlock#2); [ 79.660000] [ 79.660000] *** DEADLOCK *** [ 79.660000] [ 79.660000] May be due to missing lock nesting notation [ 79.660000] [ 79.660000] 1 lock held by swapper/0: [ 79.660000] #0: (&(&host->lock)->rlock#2){-.....}, at: [] mxs_mmc_irq_handler+0x1c/0xe8 [ 79.660000] [ 79.660000] stack backtrace: [ 79.660000] [] (unwind_backtrace+0x0/0xf4) from [] (__lock_acquire+0x1948/0x1d48) [ 79.660000] [] (__lock_acquire+0x1948/0x1d48) from [] (lock_acquire+0xe0/0xf8) [ 79.660000] [] (lock_acquire+0xe0/0xf8) from [] (_raw_spin_lock_irqsave+0x44/0x58) [ 79.660000] [] (_raw_spin_lock_irqsave+0x44/0x58) from [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) [ 79.660000] [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) from [] (mxs_mmc_irq_handler+0xd4/0xe8) [ 79.660000] [] (mxs_mmc_irq_handler+0xd4/0xe8) from [] (handle_irq_event_percpu+0x70/0x254) [ 79.660000] [] (handle_irq_event_percpu+0x70/0x254) from [] (handle_irq_event+0x3c/0x5c) [ 79.660000] [] (handle_irq_event+0x3c/0x5c) from [] (handle_level_irq+0x90/0x110) [ 79.660000] [] (handle_level_irq+0x90/0x110) from [] (generic_handle_irq+0x38/0x50) [ 79.660000] [] (generic_handle_irq+0x38/0x50) from [] (handle_IRQ+0x30/0x84) [ 79.660000] [] (handle_IRQ+0x30/0x84) from [] (__irq_svc+0x38/0x60) [ 79.660000] [] (__irq_svc+0x38/0x60) from [] (default_idle+0x2c/0x40) [ 79.660000] [] (default_idle+0x2c/0x40) from [] (cpu_idle+0x64/0xcc) [ 79.660000] [] (cpu_idle+0x64/0xcc) from [] (start_kernel+0x244/0x2c8) [ 79.660000] BUG: spinlock lockup on CPU#0, swapper/0 [ 79.660000] lock: c398cb2c, .magic: dead4ead, .owner: swapper/0, .owner_cpu: 0 [ 79.660000] [] (unwind_backtrace+0x0/0xf4) from [] (do_raw_spin_lock+0xf0/0x144) [ 79.660000] [] (do_raw_spin_lock+0xf0/0x144) from [] (_raw_spin_lock_irqsave+0x4c/0x58) [ 79.660000] [] (_raw_spin_lock_irqsave+0x4c/0x58) from [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) [ 79.660000] [] (mxs_mmc_enable_sdio_irq+0x18/0xd4) from [] (mxs_mmc_irq_handler+0xd4/0xe8) [ 79.660000] [] (mxs_mmc_irq_handler+0xd4/0xe8) from [] (handle_irq_event_percpu+0x70/0x254) [ 79.660000] [] (handle_irq_event_percpu+0x70/0x254) from [] (handle_irq_event+0x3c/0x5c) [ 79.660000] [] (handle_irq_event+0x3c/0x5c) from [] (handle_level_irq+0x90/0x110) [ 79.660000] [] (handle_level_irq+0x90/0x110) from [] (generic_handle_irq+0x38/0x50) [ 79.660000] [] (generic_handle_irq+0x38/0x50) from [] (handle_IRQ+0x30/0x84) [ 79.660000] [] (handle_IRQ+0x30/0x84) from [] (__irq_svc+0x38/0x60) [ 79.660000] [] (__irq_svc+0x38/0x60) from [] (default_idle+0x2c/0x40) [ 79.660000] [] (default_idle+0x2c/0x40) from [] (cpu_idle+0x64/0xcc) [ 79.660000] [] (cpu_idle+0x64/0xcc) from [] (start_kernel+0x244/0x2c8) Signed-off-by: Lauri Hintsala Acked-by: Shawn Guo Cc: stable Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index a51f930..e62e58e 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -285,11 +285,11 @@ static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) writel(stat & MXS_MMC_IRQ_BITS, host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_CLR); + spin_unlock(&host->lock); + if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) mmc_signal_sdio_irq(host->mmc); - spin_unlock(&host->lock); - if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ) cmd->error = -ETIMEDOUT; else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ) -- cgit v0.10.2 From fc108d24d3a6da63576a460e122fa1df0cbdea20 Mon Sep 17 00:00:00 2001 From: Lauri Hintsala Date: Tue, 17 Jul 2012 17:16:10 +0300 Subject: mmc: mxs-mmc: fix deadlock caused by recursion loop Release the lock before mmc_signal_sdio_irq is called by mxs_mmc_enable_sdio_irq. Backtrace: [ 65.470000] ============================================= [ 65.470000] [ INFO: possible recursive locking detected ] [ 65.470000] 3.5.0-rc5 #2 Not tainted [ 65.470000] --------------------------------------------- [ 65.470000] ksdioirqd/mmc0/73 is trying to acquire lock: [ 65.470000] (&(&host->lock)->rlock#2){-.-...}, at: [] mxs_mmc_enable_sdio_irq+0x18/0xdc [mxs_mmc] [ 65.470000] [ 65.470000] but task is already holding lock: [ 65.470000] (&(&host->lock)->rlock#2){-.-...}, at: [] mxs_mmc_enable_sdio_irq+0x18/0xdc [mxs_mmc] [ 65.470000] [ 65.470000] other info that might help us debug this: [ 65.470000] Possible unsafe locking scenario: [ 65.470000] [ 65.470000] CPU0 [ 65.470000] ---- [ 65.470000] lock(&(&host->lock)->rlock#2); [ 65.470000] lock(&(&host->lock)->rlock#2); [ 65.470000] [ 65.470000] *** DEADLOCK *** [ 65.470000] [ 65.470000] May be due to missing lock nesting notation [ 65.470000] [ 65.470000] 1 lock held by ksdioirqd/mmc0/73: [ 65.470000] #0: (&(&host->lock)->rlock#2){-.-...}, at: [] mxs_mmc_enable_sdio_irq+0x18/0xdc [mxs_mmc] [ 65.470000] [ 65.470000] stack backtrace: [ 65.470000] [] (unwind_backtrace+0x0/0xf4) from [] (__lock_acquire+0x14f8/0x1b98) [ 65.470000] [] (__lock_acquire+0x14f8/0x1b98) from [] (lock_acquire+0xa0/0x108) [ 65.470000] [] (lock_acquire+0xa0/0x108) from [] (_raw_spin_lock_irqsave+0x48/0x5c) [ 65.470000] [] (_raw_spin_lock_irqsave+0x48/0x5c) from [] (mxs_mmc_enable_sdio_irq+0x18/0xdc [mxs_mmc]) [ 65.470000] [] (mxs_mmc_enable_sdio_irq+0x18/0xdc [mxs_mmc]) from [] (mxs_mmc_enable_sdio_irq+0xc8/0xdc [mxs_mmc]) [ 65.470000] [] (mxs_mmc_enable_sdio_irq+0xc8/0xdc [mxs_mmc]) from [] (sdio_irq_thread+0x1bc/0x274) [ 65.470000] [] (sdio_irq_thread+0x1bc/0x274) from [] (kthread+0x8c/0x98) [ 65.470000] [] (kthread+0x8c/0x98) from [] (kernel_thread_exit+0x0/0x8) [ 65.470000] BUG: spinlock lockup suspected on CPU#0, ksdioirqd/mmc0/73 [ 65.470000] lock: 0xc3358724, .magic: dead4ead, .owner: ksdioirqd/mmc0/73, .owner_cpu: 0 [ 65.470000] [] (unwind_backtrace+0x0/0xf4) from [] (do_raw_spin_lock+0x100/0x144) [ 65.470000] [] (do_raw_spin_lock+0x100/0x144) from [] (_raw_spin_lock_irqsave+0x50/0x5c) [ 65.470000] [] (_raw_spin_lock_irqsave+0x50/0x5c) from [] (mxs_mmc_enable_sdio_irq+0x18/0xdc [mxs_mmc]) [ 65.470000] [] (mxs_mmc_enable_sdio_irq+0x18/0xdc [mxs_mmc]) from [] (mxs_mmc_enable_sdio_irq+0xc8/0xdc [mxs_mmc]) [ 65.470000] [] (mxs_mmc_enable_sdio_irq+0xc8/0xdc [mxs_mmc]) from [] (sdio_irq_thread+0x1bc/0x274) [ 65.470000] [] (sdio_irq_thread+0x1bc/0x274) from [] (kthread+0x8c/0x98) [ 65.470000] [] (kthread+0x8c/0x98) from [] (kernel_thread_exit+0x0/0x8) Reported-by: Attila Kinali Signed-off-by: Lauri Hintsala Acked-by: Shawn Guo Cc: stable Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index e62e58e..ad3fcea 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -644,11 +644,6 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); writel(BM_SSP_CTRL1_SDIO_IRQ_EN, host->base + HW_SSP_CTRL1(host) + STMP_OFFSET_REG_SET); - - if (readl(host->base + HW_SSP_STATUS(host)) & - BM_SSP_STATUS_SDIO_IRQ) - mmc_signal_sdio_irq(host->mmc); - } else { writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, host->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_CLR); @@ -657,6 +652,11 @@ static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) } spin_unlock_irqrestore(&host->lock, flags); + + if (enable && readl(host->base + HW_SSP_STATUS(host)) & + BM_SSP_STATUS_SDIO_IRQ) + mmc_signal_sdio_irq(host->mmc); + } static const struct mmc_host_ops mxs_mmc_ops = { -- cgit v0.10.2 From 74f330bceaa7b88d06062e1cac3d519a3dfc041e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 22 Aug 2012 23:10:01 +0800 Subject: mmc: sdhci-esdhc: break out early if clock is 0 Since commit 30832ab56 ("mmc: sdhci: Always pass clock request value zero to set_clock host op") was merged, esdhc_set_clock starts hitting "if (clock == 0)" where ESDHC_SYSTEM_CONTROL has been operated. This causes SDHCI card-detection function being broken. Fix the regression by moving "if (clock == 0)" above ESDHC_SYSTEM_CONTROL operation. Signed-off-by: Shawn Guo Cc: Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index b97b2f5..d25f9ab 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -48,14 +48,14 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock) int div = 1; u32 temp; + if (clock == 0) + goto out; + temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); - if (clock == 0) - goto out; - while (host->max_clk / pre_div / 16 > clock && pre_div < 256) pre_div *= 2; -- cgit v0.10.2 From 077d40731edc90ee9dedf63249034c8cd5f694ce Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 24 Jul 2012 11:42:04 +0200 Subject: mmc: atmel-mci: not busy flag has also to be used for read operations Even if the datasheet says that the not busy flag has to be used only for write operations, it's false except for version lesser than v2xx. Not waiting on the not busy flag for read operations can cause the controller to hang-up during the initialization of some SD cards with DMA after the first CMD6 -- the next command is sent too early. Signed-off-by: Ludovic Desroches Cc: stable [3.5, 3.6] Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 322412c..a53c7c4 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -81,6 +81,7 @@ struct atmel_mci_caps { bool has_bad_data_ordering; bool need_reset_after_xfer; bool need_blksz_mul_4; + bool need_notbusy_for_read_ops; }; struct atmel_mci_dma { @@ -1625,7 +1626,8 @@ static void atmci_tasklet_func(unsigned long priv) __func__); atmci_set_completed(host, EVENT_XFER_COMPLETE); - if (host->data->flags & MMC_DATA_WRITE) { + if (host->caps.need_notbusy_for_read_ops || + (host->data->flags & MMC_DATA_WRITE)) { atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY); state = STATE_WAITING_NOTBUSY; } else if (host->mrq->stop) { @@ -2218,6 +2220,7 @@ static void __init atmci_get_cap(struct atmel_mci *host) host->caps.has_bad_data_ordering = 1; host->caps.need_reset_after_xfer = 1; host->caps.need_blksz_mul_4 = 1; + host->caps.need_notbusy_for_read_ops = 0; /* keep only major version number */ switch (version & 0xf00) { @@ -2238,6 +2241,7 @@ static void __init atmci_get_cap(struct atmel_mci *host) case 0x200: host->caps.has_rwproof = 1; host->caps.need_blksz_mul_4 = 0; + host->caps.need_notbusy_for_read_ops = 1; case 0x100: host->caps.has_bad_data_ordering = 0; host->caps.need_reset_after_xfer = 0; -- cgit v0.10.2 From 182c90815993452f1902837cc342ac2c05ef13f5 Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Wed, 1 Aug 2012 09:30:30 +0900 Subject: mmc: dw_mmc: amend using error interrupt status RINTSTS status includes masked interrupts as well as unmasked. data_status and cmd_status are set by value of RINTSTS in interrupt handler and tasklet finally uses it to decide whether error is happened or not. In addition, MINTSTS status is used for setting data_status in PIO. Masked error interrupt will not be handled and that status can be considered non-error case. Signed-off-by: Seungwon Jeon Reviewed By: Girish K S Acked-by: Jaehoon Chung Acked-by: Will Newton Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 72dc3cd..7baed45 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1547,12 +1547,11 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status) static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) { struct dw_mci *host = dev_id; - u32 status, pending; + u32 pending; unsigned int pass_count = 0; int i; do { - status = mci_readl(host, RINTSTS); pending = mci_readl(host, MINTSTS); /* read-only mask reg */ /* @@ -1570,7 +1569,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & DW_MCI_CMD_ERROR_FLAGS) { mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); - host->cmd_status = status; + host->cmd_status = pending; smp_wmb(); set_bit(EVENT_CMD_COMPLETE, &host->pending_events); } @@ -1578,7 +1577,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & DW_MCI_DATA_ERROR_FLAGS) { /* if there is an error report DATA_ERROR */ mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS); - host->data_status = status; + host->data_status = pending; smp_wmb(); set_bit(EVENT_DATA_ERROR, &host->pending_events); if (!(pending & (SDMMC_INT_DTO | SDMMC_INT_DCRC | @@ -1589,7 +1588,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_DATA_OVER) { mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); if (!host->data_status) - host->data_status = status; + host->data_status = pending; smp_wmb(); if (host->dir_status == DW_MCI_RECV_STATUS) { if (host->sg != NULL) @@ -1613,7 +1612,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_CMD_DONE) { mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE); - dw_mci_cmd_interrupt(host, status); + dw_mci_cmd_interrupt(host, pending); } if (pending & SDMMC_INT_CD) { -- cgit v0.10.2 From 9b2026a12511439d906a5d8d302ae285ebe7378a Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Wed, 1 Aug 2012 09:30:40 +0900 Subject: mmc: dw_mmc: correct mishandling error interrupt Datasheet of SYNOPSYS mentions that DTO(Data Transfer Over) interrupt will be raised even if some error interrupts, however it is actually found that DTO does not occur. SYNOPSYS has confirmed this issue. Current implementation defers the call of tasklet_schedule until DTO when the error interrupts is happened. This patch fixes error handling. Signed-off-by: Seungwon Jeon Acked-by: Jaehoon Chung Acked-by: Will Newton Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7baed45..1a5db20 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1580,9 +1580,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) host->data_status = pending; smp_wmb(); set_bit(EVENT_DATA_ERROR, &host->pending_events); - if (!(pending & (SDMMC_INT_DTO | SDMMC_INT_DCRC | - SDMMC_INT_SBE | SDMMC_INT_EBE))) - tasklet_schedule(&host->tasklet); + tasklet_schedule(&host->tasklet); } if (pending & SDMMC_INT_DATA_OVER) { -- cgit v0.10.2 From e74f3a9c993a088f0a067e13941075e4acb7300a Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Wed, 1 Aug 2012 09:30:46 +0900 Subject: mmc: dw_mmc: fix error handling in PIO mode Data transfer will be continued until all the bytes are transmitted, even if data crc error occurs during a multiple-block data transfer. This means RXDR/TXDR interrupts will occurs until data transfer is terminated. Early setting of host->sg to NULL prevents going into xxx_data_pio functions, hence permanent unhandled RXDR/TXDR interrupts occurs. And checking error interrupt status in the xxx_data_pio functions is no need because dw_mci_interrupt does do the same. This patch also removes it. Signed-off-by: Seungwon Jeon Acked-by: Jaehoon Chung Acked-by: Will Newton Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 1a5db20..cf8511b 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1429,22 +1429,10 @@ static void dw_mci_read_data_pio(struct dw_mci *host) nbytes += len; remain -= len; } while (remain); - sg_miter->consumed = offset; + sg_miter->consumed = offset; status = mci_readl(host, MINTSTS); mci_writel(host, RINTSTS, SDMMC_INT_RXDR); - if (status & DW_MCI_DATA_ERROR_FLAGS) { - host->data_status = status; - data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; - smp_wmb(); - - set_bit(EVENT_DATA_ERROR, &host->pending_events); - - tasklet_schedule(&host->tasklet); - return; - } } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ data->bytes_xfered += nbytes; @@ -1497,23 +1485,10 @@ static void dw_mci_write_data_pio(struct dw_mci *host) nbytes += len; remain -= len; } while (remain); - sg_miter->consumed = offset; + sg_miter->consumed = offset; status = mci_readl(host, MINTSTS); mci_writel(host, RINTSTS, SDMMC_INT_TXDR); - if (status & DW_MCI_DATA_ERROR_FLAGS) { - host->data_status = status; - data->bytes_xfered += nbytes; - sg_miter_stop(sg_miter); - host->sg = NULL; - - smp_wmb(); - - set_bit(EVENT_DATA_ERROR, &host->pending_events); - - tasklet_schedule(&host->tasklet); - return; - } } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ data->bytes_xfered += nbytes; -- cgit v0.10.2 From 9623b5b9192b349bcadb31cce159072a78ac6972 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 25 Jul 2012 08:33:17 -0700 Subject: mmc: dw_mmc: Disable low power mode if SDIO interrupts are used The documentation for the dw_mmc part says that the low power mode should normally only be set for MMC and SD memory and should be turned off for SDIO cards that need interrupts detected. The best place I could find to do this is when the SDIO interrupt was first enabled. I rely on the fact that dw_mci_setup_bus() will be called when it's time to reenable. Signed-off-by: Doug Anderson Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index cf8511b..af40d22 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -627,6 +627,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot) { struct dw_mci *host = slot->host; u32 div; + u32 clk_en_a; if (slot->clock != host->current_speed) { div = host->bus_hz / slot->clock; @@ -659,9 +660,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot) mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); - /* enable clock */ - mci_writel(host, CLKENA, ((SDMMC_CLKEN_ENABLE | - SDMMC_CLKEN_LOW_PWR) << slot->id)); + /* enable clock; only low power if no SDIO */ + clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; + if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id))) + clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id; + mci_writel(host, CLKENA, clk_en_a); /* inform CIU */ mci_send_cmd(slot, @@ -862,6 +865,30 @@ static int dw_mci_get_cd(struct mmc_host *mmc) return present; } +/* + * Disable lower power mode. + * + * Low power mode will stop the card clock when idle. According to the + * description of the CLKENA register we should disable low power mode + * for SDIO cards if we need SDIO interrupts to work. + * + * This function is fast if low power mode is already disabled. + */ +static void dw_mci_disable_low_power(struct dw_mci_slot *slot) +{ + struct dw_mci *host = slot->host; + u32 clk_en_a; + const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id; + + clk_en_a = mci_readl(host, CLKENA); + + if (clk_en_a & clken_low_pwr) { + mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr); + mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | + SDMMC_CMD_PRV_DAT_WAIT, 0); + } +} + static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) { struct dw_mci_slot *slot = mmc_priv(mmc); @@ -871,6 +898,14 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) /* Enable/disable Slot Specific SDIO interrupt */ int_mask = mci_readl(host, INTMASK); if (enb) { + /* + * Turn off low power mode if it was enabled. This is a bit of + * a heavy operation and we disable / enable IRQs a lot, so + * we'll leave low power mode disabled and it will get + * re-enabled again in dw_mci_setup_bus(). + */ + dw_mci_disable_low_power(slot); + mci_writel(host, INTMASK, (int_mask | SDMMC_INT_SDIO(slot->id))); } else { -- cgit v0.10.2 From 3550ccdb9d8d350e526b809bf3dd92b550a74fe1 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Wed, 29 Aug 2012 15:05:36 +0900 Subject: mmc: card: Skip secure erase on MoviNAND; causes unrecoverable corruption. For several MoviNAND eMMC parts, there are known issues with secure erase and secure trim. For these specific MoviNAND devices, we skip these operations. Specifically, there is a bug in the eMMC firmware that causes unrecoverable corruption when the MMC is erased with MMC_CAP_ERASE enabled. References: http://forum.xda-developers.com/showthread.php?t=1644364 https://plus.google.com/111398485184813224730/posts/21pTYfTsCkB#111398485184813224730/posts/21pTYfTsCkB Signed-off-by: Ian Chen Reviewed-by: Namjae Jeon Acked-by: Jaehoon Chung Reviewed-by: Linus Walleij Cc: stable [3.0+] Signed-off-by: Chris Ball diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f1c84de..172a768 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1411,7 +1411,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) /* complete ongoing async transfer before issuing discard */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); - if (req->cmd_flags & REQ_SECURE) + if (req->cmd_flags & REQ_SECURE && + !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN)) ret = mmc_blk_issue_secdiscard_rq(mq, req); else ret = mmc_blk_issue_discard_rq(mq, req); @@ -1716,6 +1717,7 @@ force_ro_fail: #define CID_MANFID_SANDISK 0x2 #define CID_MANFID_TOSHIBA 0x11 #define CID_MANFID_MICRON 0x13 +#define CID_MANFID_SAMSUNG 0x15 static const struct mmc_fixup blk_fixups[] = { @@ -1752,6 +1754,28 @@ static const struct mmc_fixup blk_fixups[] = MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc, MMC_QUIRK_LONG_READ_TIME), + /* + * On these Samsung MoviNAND parts, performing secure erase or + * secure trim can result in unrecoverable corruption due to a + * firmware bug. + */ + MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + END_FIXUP }; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 111aca5..4b27f9f 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -239,6 +239,7 @@ struct mmc_card { #define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */ #define MMC_QUIRK_BROKEN_BYTE_MODE_512 (1<<8) /* Avoid sending 512 bytes in */ #define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */ +#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */ /* byte mode */ unsigned int poweroff_notify_state; /* eMMC4.5 notify feature */ #define MMC_NO_POWER_NOTIFICATION 0 -- cgit v0.10.2 From 75b53aee2f4fe6375c6007226bf68d75b5c4a929 Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Fri, 24 Aug 2012 06:00:18 +0000 Subject: mmc: omap: fix broken PIO mode After commit 26b88520b80695a6fa5fd95b5d97c03f4daf87e0 ("mmc: omap_hsmmc: remove private DMA API implementation"), the Nokia N800 here stopped booting: [ 2.086181] Waiting for root device /dev/mmcblk0p1... [ 2.324066] Unhandled fault: imprecise external abort (0x406) at 0x00000000 [ 2.331451] Internal error: : 406 [#1] ARM [ 2.335784] Modules linked in: [ 2.339050] CPU: 0 Not tainted (3.6.0-rc3 #60) [ 2.344146] PC is at default_idle+0x28/0x30 [ 2.348602] LR is at trace_hardirqs_on_caller+0x15c/0x1b0 ... This turned out to be due to memory corruption caused by long-broken PIO code in drivers/mmc/host/omap.c. (Previously, this driver had been using DMA; but the above commit caused the MMC driver to fall back to PIO mode with an unmodified Kconfig.) The PIO code, added with the rest of the driver in commit 730c9b7e6630f786fcec026fb11d2e6f2c90fdcb ("[MMC] Add OMAP MMC host driver"), confused bytes with 16-bit words. This bug caused memory located after the PIO transfer buffer to be corrupted with transfers larger than 32 bytes. The driver also did not increment the buffer pointer after the transfer occurred. This bug resulted in data corruption during any transfer larger than 64 bytes. Signed-off-by: Paul Walmsley Reviewed-by: Felipe Balbi Tested-by: Tony Lindgren Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 50e08f0..a5999a7 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -668,7 +668,7 @@ mmc_omap_clk_timer(unsigned long data) static void mmc_omap_xfer_data(struct mmc_omap_host *host, int write) { - int n; + int n, nwords; if (host->buffer_bytes_left == 0) { host->sg_idx++; @@ -678,15 +678,23 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write) n = 64; if (n > host->buffer_bytes_left) n = host->buffer_bytes_left; + + nwords = n / 2; + nwords += n & 1; /* handle odd number of bytes to transfer */ + host->buffer_bytes_left -= n; host->total_bytes_left -= n; host->data->bytes_xfered += n; if (write) { - __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); + __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), + host->buffer, nwords); } else { - __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n); + __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), + host->buffer, nwords); } + + host->buffer += nwords; } static inline void mmc_omap_report_irq(u16 status) -- cgit v0.10.2 From e829c66745e66558b624fd635be4a384fe854944 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Aug 2012 19:22:36 +0200 Subject: ARM: gemini: fix the gemini build Test-compiling obscure machines I notice that the gemini (which by the way lacks a defconfig) is broken since some time back. Adding a simple missing include makes it build again. Signed-off-by: Linus Walleij Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c index ca70e5f..020852d 100644 --- a/arch/arm/mach-gemini/irq.c +++ b/arch/arm/mach-gemini/irq.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define IRQ_SOURCE(base_addr) (base_addr + 0x00) -- cgit v0.10.2 From 79c5fcebfe4021f326a6715009f0b6b622d5df92 Mon Sep 17 00:00:00 2001 From: Jesse Larrew Date: Thu, 7 Jun 2012 16:04:34 -0500 Subject: powerpc/vphn: Fix arch_update_cpu_topology() return value arch_update_cpu_topology() should only return 1 when the topology has actually changed, and should return 0 otherwise. This patch fixes a potential bug where rebuild_sched_domains() would reinitialize the sched domains even when the topology hasn't changed. Signed-off-by: Jesse Larrew Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 39b1597..59213cf 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1436,11 +1436,11 @@ static long vphn_get_associativity(unsigned long cpu, /* * Update the node maps and sysfs entries for each cpu whose home node - * has changed. + * has changed. Returns 1 when the topology has changed, and 0 otherwise. */ int arch_update_cpu_topology(void) { - int cpu, nid, old_nid; + int cpu, nid, old_nid, changed = 0; unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0}; struct device *dev; @@ -1466,9 +1466,10 @@ int arch_update_cpu_topology(void) dev = get_cpu_device(cpu); if (dev) kobject_uevent(&dev->kobj, KOBJ_CHANGE); + changed = 1; } - return 1; + return changed; } static void topology_work_fn(struct work_struct *work) -- cgit v0.10.2 From dabe859ec6360a12e71f39bf695d174e19ff2688 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 26 Jul 2012 13:56:11 +0000 Subject: powerpc: Give hypervisor decrementer interrupts their own handler At the moment the handler for hypervisor decrementer interrupts is the same as for decrementer interrupts, i.e. timer_interrupt(). This is bogus; if we ever do get a hypervisor decrementer interrupt it won't have anything to do with the next timer event. In fact the only time we get hypervisor decrementer interrupts is when one is left pending on exit from a KVM guest. When we get a hypervisor decrementer interrupt we don't need to do anything special to clear it, since they are edge-triggered on the transition of HDEC from 0 to -1. Thus this adds an empty handler function for them. We don't need to have them masked when interrupts are soft-disabled, so we use STD_EXCEPTION_HV instead of MASKABLE_EXCEPTION_HV. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index e894515..39aa97d 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -186,7 +186,7 @@ hardware_interrupt_hv: KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x800) MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer) - MASKABLE_EXCEPTION_HV(0x980, 0x982, decrementer) + STD_EXCEPTION_HV(0x980, 0x982, hdecrementer) STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a) KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xa00) @@ -486,6 +486,7 @@ machine_check_common: STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) + STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt) STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index be171ee..e49e931 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -535,6 +535,15 @@ void timer_interrupt(struct pt_regs * regs) trace_timer_interrupt_exit(regs); } +/* + * Hypervisor decrementer interrupts shouldn't occur but are sometimes + * left pending on exit from a KVM guest. We don't need to do anything + * to clear them, as they are edge-triggered. + */ +void hdec_interrupt(struct pt_regs *regs) +{ +} + #ifdef CONFIG_SUSPEND static void generic_suspend_disable_irqs(void) { -- cgit v0.10.2 From 375f561a4131a0f501c8845a2a20f2ca1abc8f7a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 26 Jul 2012 18:51:09 +0000 Subject: powerpc/powernv: Always go into nap mode when CPU is offline The CPU hotplug code for the powernv platform currently only puts offline CPUs into nap mode if the powersave_nap variable is set. However, HV-style KVM on this platform requires secondary CPU threads to be offline and in nap mode. Since we know nap mode works just fine on all POWER7 machines, and the only machines that support the powernv platform are POWER7 machines, this changes the code to always put offline CPUs into nap mode, regardless of powersave_nap. Powersave_nap still controls whether or not CPUs go into nap mode when idle, as before. Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 53b6dfa..54b73a2 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -386,6 +386,7 @@ extern unsigned long cpuidle_disable; enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF}; extern int powersave_nap; /* set if nap mode can be used in idle loop */ +extern void power7_nap(void); #ifdef CONFIG_PSERIES_IDLE extern void update_smt_snooze_delay(int snooze); diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index 7140d83..e11863f 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -28,7 +28,9 @@ _GLOBAL(power7_idle) lwz r4,ADDROFF(powersave_nap)(r3) cmpwi 0,r4,0 beqlr + /* fall through */ +_GLOBAL(power7_nap) /* NAP is a state loss, we create a regs frame on the * stack, fill it up with the state we care about and * stick a pointer to it in PACAR1. We really only diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 3ef4625..7698b6e 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -106,14 +106,6 @@ static void pnv_smp_cpu_kill_self(void) { unsigned int cpu; - /* If powersave_nap is enabled, use NAP mode, else just - * spin aimlessly - */ - if (!powersave_nap) { - generic_mach_cpu_die(); - return; - } - /* Standard hot unplug procedure */ local_irq_disable(); idle_task_exit(); @@ -128,7 +120,7 @@ static void pnv_smp_cpu_kill_self(void) */ mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); while (!generic_check_cpu_restart(cpu)) { - power7_idle(); + power7_nap(); if (!generic_check_cpu_restart(cpu)) { DBG("CPU%d Unexpected exit while offline !\n", cpu); /* We may be getting an IPI, so we re-enable -- cgit v0.10.2 From 1b6ca2a6fe56e7697d57348646e07df08f43b1bb Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:47:56 +0000 Subject: powerpc: Update DSCR on all CPUs when writing sysfs dscr_default Writing to dscr_default in sysfs doesn't actually change the DSCR - we rely on a context switch on each CPU to do the work. There is no guarantee we will get a context switch in a reasonable amount of time so fire off an IPI to force an immediate change. This issue was found with the following test case: http://ozlabs.org/~anton/junkcode/dscr_explicit_test.c Signed-off-by: Anton Blanchard Cc: # 3.0+ Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 3529446..d4cbbd1 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -194,6 +194,12 @@ static ssize_t show_dscr_default(struct device *dev, return sprintf(buf, "%lx\n", dscr_default); } +static void update_dscr(void *dummy) +{ + if (!current->thread.dscr_inherit) + mtspr(SPRN_DSCR, dscr_default); +} + static ssize_t __used store_dscr_default(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -206,6 +212,8 @@ static ssize_t __used store_dscr_default(struct device *dev, return -EINVAL; dscr_default = val; + on_each_cpu(update_dscr, NULL, 1); + return count; } -- cgit v0.10.2 From 00ca0de02f80924dfff6b4f630e1dff3db005e35 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:48:46 +0000 Subject: powerpc: Keep thread.dscr and thread.dscr_inherit in sync When we update the DSCR either via emulation of mtspr(DSCR) or via a change to dscr_default in sysfs we don't update thread.dscr. We will eventually update it at context switch time but there is a period where thread.dscr is incorrect. If we fork at this point we will copy the old value of thread.dscr into the child. To avoid this, always keep thread.dscr in sync with reality. This issue was found with the following testcase: http://ozlabs.org/~anton/junkcode/dscr_inherit_test.c Signed-off-by: Anton Blanchard Cc: # 3.0+ Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index d4cbbd1..8302af6 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -196,8 +196,10 @@ static ssize_t show_dscr_default(struct device *dev, static void update_dscr(void *dummy) { - if (!current->thread.dscr_inherit) + if (!current->thread.dscr_inherit) { + current->thread.dscr = dscr_default; mtspr(SPRN_DSCR, dscr_default); + } } static ssize_t __used store_dscr_default(struct device *dev, diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 1589723..ae0843f 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -972,8 +972,9 @@ static int emulate_instruction(struct pt_regs *regs) cpu_has_feature(CPU_FTR_DSCR)) { PPC_WARN_EMULATED(mtdscr, regs); rd = (instword >> 21) & 0x1f; - mtspr(SPRN_DSCR, regs->gpr[rd]); + current->thread.dscr = regs->gpr[rd]; current->thread.dscr_inherit = 1; + mtspr(SPRN_DSCR, current->thread.dscr); return 0; } #endif -- cgit v0.10.2 From 1021cb268b3025573c4811f1dee4a11260c4507b Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:49:47 +0000 Subject: powerpc: Fix DSCR inheritance in copy_thread() If the default DSCR is non zero we set thread.dscr_inherit in copy_thread() meaning the new thread and all its children will ignore future updates to the default DSCR. This is not intended and is a change in behaviour that a number of our users have hit. We just need to inherit thread.dscr and thread.dscr_inherit from the parent which ends up being much simpler. This was found with the following test case: http://ozlabs.org/~anton/junkcode/dscr_default_test.c Signed-off-by: Anton Blanchard Cc: # 3.0+ Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 710f400..1a1f2dd 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -802,16 +802,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, #endif /* CONFIG_PPC_STD_MMU_64 */ #ifdef CONFIG_PPC64 if (cpu_has_feature(CPU_FTR_DSCR)) { - if (current->thread.dscr_inherit) { - p->thread.dscr_inherit = 1; - p->thread.dscr = current->thread.dscr; - } else if (0 != dscr_default) { - p->thread.dscr_inherit = 1; - p->thread.dscr = dscr_default; - } else { - p->thread.dscr_inherit = 0; - p->thread.dscr = 0; - } + p->thread.dscr_inherit = current->thread.dscr_inherit; + p->thread.dscr = current->thread.dscr; } #endif -- cgit v0.10.2 From 714332858bfd40dcf8f741498336d93875c23aa7 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Sep 2012 16:51:10 +0000 Subject: powerpc: Restore correct DSCR in context switch During a context switch we always restore the per thread DSCR value. If we aren't doing explicit DSCR management (ie thread.dscr_inherit == 0) and the default DSCR changed while the process has been sleeping we end up with the wrong value. Check thread.dscr_inherit and select the default DSCR or per thread DSCR as required. This was found with the following test case, when running with more threads than CPUs (ie forcing context switching): http://ozlabs.org/~anton/junkcode/dscr_default_test.c With the four patches applied I can run a combination of all test cases successfully at the same time: http://ozlabs.org/~anton/junkcode/dscr_default_test.c http://ozlabs.org/~anton/junkcode/dscr_explicit_test.c http://ozlabs.org/~anton/junkcode/dscr_inherit_test.c Signed-off-by: Anton Blanchard Cc: # 3.0+ Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 85b05c4..e899572 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -76,6 +76,7 @@ int main(void) DEFINE(SIGSEGV, SIGSEGV); DEFINE(NMI_MASK, NMI_MASK); DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr)); + DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit)); #else DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); #endif /* CONFIG_PPC64 */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 4b01a25..b40e0b4 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -370,6 +370,12 @@ _GLOBAL(ret_from_fork) li r3,0 b syscall_exit + .section ".toc","aw" +DSCR_DEFAULT: + .tc dscr_default[TC],dscr_default + + .section ".text" + /* * This routine switches between two different tasks. The process * state of one is saved on its kernel stack. Then the state @@ -509,9 +515,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) mr r1,r8 /* start using new stack pointer */ std r7,PACAKSAVE(r13) - ld r6,_CCR(r1) - mtcrf 0xFF,r6 - #ifdef CONFIG_ALTIVEC BEGIN_FTR_SECTION ld r0,THREAD_VRSAVE(r4) @@ -520,14 +523,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_PPC64 BEGIN_FTR_SECTION + lwz r6,THREAD_DSCR_INHERIT(r4) + ld r7,DSCR_DEFAULT@toc(2) ld r0,THREAD_DSCR(r4) - cmpd r0,r25 - beq 1f + cmpwi r6,0 + bne 1f + ld r0,0(r7) +1: cmpd r0,r25 + beq 2f mtspr SPRN_DSCR,r0 -1: +2: END_FTR_SECTION_IFSET(CPU_FTR_DSCR) #endif + ld r6,_CCR(r1) + mtcrf 0xFF,r6 + /* r3-r13 are destroyed -- Cort */ REST_8GPRS(14, r1) REST_10GPRS(22, r1) -- cgit v0.10.2 From 9fb1b36ca1234e64a5d1cc573175303395e3354d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 4 Sep 2012 18:33:08 +0000 Subject: powerpc: Make sure IPI handlers see data written by IPI senders We have been observing hangs, both of KVM guest vcpu tasks and more generally, where a process that is woken doesn't properly wake up and continue to run, but instead sticks in TASK_WAKING state. This happens because the update of rq->wake_list in ttwu_queue_remote() is not ordered with the update of ipi_message in smp_muxed_ipi_message_pass(), and the reading of rq->wake_list in scheduler_ipi() is not ordered with the reading of ipi_message in smp_ipi_demux(). Thus it is possible for the IPI receiver not to see the updated rq->wake_list and therefore conclude that there is nothing for it to do. In order to make sure that anything done before smp_send_reschedule() is ordered before anything done in the resulting call to scheduler_ipi(), this adds barriers in smp_muxed_message_pass() and smp_ipi_demux(). The barrier in smp_muxed_message_pass() is a full barrier to ensure that there is a full ordering between the smp_send_reschedule() caller and scheduler_ipi(). In smp_ipi_demux(), we use xchg() rather than xchg_local() because xchg() includes release and acquire barriers. Using xchg() rather than xchg_local() makes sense given that ipi_message is not just accessed locally. This moves the barrier between setting the message and calling the cause_ipi() function into the individual cause_ipi implementations. Most of them -- those that used outb, out_8 or similar -- already had a full barrier because out_8 etc. include a sync before the MMIO store. This adds an explicit barrier in the two remaining cases. These changes made no measurable difference to the speed of IPIs as measured using a simple ping-pong latency test across two CPUs on different cores of a POWER7 machine. The analysis of the reason why processes were not waking up properly is due to Milton Miller. Cc: stable@vger.kernel.org # v3.0+ Reported-by: Milton Miller Signed-off-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 5b25c80..a892680 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -28,6 +28,8 @@ void doorbell_setup_this_cpu(void) void doorbell_cause_ipi(int cpu, unsigned long data) { + /* Order previous accesses vs. msgsnd, which is treated as a store */ + mb(); ppc_msgsnd(PPC_DBELL, 0, data); } diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 0321007..8d4214a 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -198,8 +198,15 @@ void smp_muxed_ipi_message_pass(int cpu, int msg) struct cpu_messages *info = &per_cpu(ipi_message, cpu); char *message = (char *)&info->messages; + /* + * Order previous accesses before accesses in the IPI handler. + */ + smp_mb(); message[msg] = 1; - mb(); + /* + * cause_ipi functions are required to include a full barrier + * before doing whatever causes the IPI. + */ smp_ops->cause_ipi(cpu, info->data); } @@ -211,7 +218,7 @@ irqreturn_t smp_ipi_demux(void) mb(); /* order any irq clear */ do { - all = xchg_local(&info->messages, 0); + all = xchg(&info->messages, 0); #ifdef __BIG_ENDIAN if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION))) diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c index 14469cf..df0fc58 100644 --- a/arch/powerpc/sysdev/xics/icp-hv.c +++ b/arch/powerpc/sysdev/xics/icp-hv.c @@ -65,7 +65,11 @@ static inline void icp_hv_set_xirr(unsigned int value) static inline void icp_hv_set_qirr(int n_cpu , u8 value) { int hw_cpu = get_hard_smp_processor_id(n_cpu); - long rc = plpar_hcall_norets(H_IPI, hw_cpu, value); + long rc; + + /* Make sure all previous accesses are ordered before IPI sending */ + mb(); + rc = plpar_hcall_norets(H_IPI, hw_cpu, value); if (rc != H_SUCCESS) { pr_err("%s: bad return code qirr cpu=%d hw_cpu=%d mfrr=0x%x " "returned %ld\n", __func__, n_cpu, hw_cpu, value, rc); -- cgit v0.10.2 From 636802ef96eebe279b22ad9f9dacfe29291e45c7 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 4 Sep 2012 15:08:28 +0000 Subject: powerpc: Don't use __put_user() in patch_instruction patch_instruction() can be called very early on ppc32, when the kernel isn't yet running at it's linked address. That can cause the ! is_kernel_addr() test in __put_user() to trip and call might_sleep() which is very bad at that point during boot. Use a lower level function instead for now, at least until we get to rework ppc32 boot process to do the code patching later, like ppc64 does. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index dd223b3..17e5b23 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -20,7 +20,7 @@ int patch_instruction(unsigned int *addr, unsigned int instr) { int err; - err = __put_user(instr, addr); + __put_user_size(instr, addr, 4, err); if (err) return err; asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr)); -- cgit v0.10.2 From 50e900417b8096939d12a46848f965e27a905e36 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 4 Sep 2012 15:45:17 -0400 Subject: xen/p2m: Fix one-off error in checking the P2M tree directory. We would traverse the full P2M top directory (from 0->MAX_DOMAIN_PAGES inclusive) when trying to figure out whether we can re-use some of the P2M middle leafs. Which meant that if the kernel was compiled with MAX_DOMAIN_PAGES=512 we would try to use the 512th entry. Fortunately for us the p2m_top_index has a check for this: BUG_ON(pfn >= MAX_P2M_PFN); which we hit and saw this: (XEN) domain_crash_sync called from entry.S (XEN) Domain 0 (vcpu#0) crashed on cpu#0: (XEN) ----[ Xen-4.1.2-OVM x86_64 debug=n Tainted: C ]---- (XEN) CPU: 0 (XEN) RIP: e033:[] (XEN) RFLAGS: 0000000000000212 EM: 1 CONTEXT: pv guest (XEN) rax: ffffffff81db5000 rbx: ffffffff81db4000 rcx: 0000000000000000 (XEN) rdx: 0000000000480211 rsi: 0000000000000000 rdi: ffffffff81db4000 (XEN) rbp: ffffffff81793db8 rsp: ffffffff81793d38 r8: 0000000008000000 (XEN) r9: 4000000000000000 r10: 0000000000000000 r11: ffffffff81db7000 (XEN) r12: 0000000000000ff8 r13: ffffffff81df1ff8 r14: ffffffff81db6000 (XEN) r15: 0000000000000ff8 cr0: 000000008005003b cr4: 00000000000026f0 (XEN) cr3: 0000000661795000 cr2: 0000000000000000 Fixes-Oracle-Bug: 14570662 CC: stable@vger.kernel.org # only for v3.5 Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index d4b2554..76ba0e9 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -599,7 +599,7 @@ bool __init early_can_reuse_p2m_middle(unsigned long set_pfn, unsigned long set_ if (p2m_index(set_pfn)) return false; - for (pfn = 0; pfn <= MAX_DOMAIN_PAGES; pfn += P2M_PER_PAGE) { + for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_PER_PAGE) { topidx = p2m_top_index(pfn); if (!p2m_top[topidx]) -- cgit v0.10.2 From ce7184bdbd38d920fb515266fbbdc585ad2e5493 Mon Sep 17 00:00:00 2001 From: Alex Shi Date: Fri, 24 Aug 2012 08:55:13 +0000 Subject: xen: fix logical error in tlb flushing While TLB_FLUSH_ALL gets passed as 'end' argument to flush_tlb_others(), the Xen code was made to check its 'start' parameter. That may give a incorrect op.cmd to MMUEXT_INVLPG_MULTI instead of MMUEXT_TLB_FLUSH_MULTI. Then it causes some page can not be flushed from TLB. This patch fixed this issue. Reported-by: Jan Beulich Signed-off-by: Alex Shi Acked-by: Jan Beulich Tested-by: Yongjie Ren Signed-off-by: Konrad Rzeszutek Wilk diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index b65a761..5141d80 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -1283,7 +1283,7 @@ static void xen_flush_tlb_others(const struct cpumask *cpus, cpumask_clear_cpu(smp_processor_id(), to_cpumask(args->mask)); args->op.cmd = MMUEXT_TLB_FLUSH_MULTI; - if (start != TLB_FLUSH_ALL && (end - start) <= PAGE_SIZE) { + if (end != TLB_FLUSH_ALL && (end - start) <= PAGE_SIZE) { args->op.cmd = MMUEXT_INVLPG_MULTI; args->op.arg1.linear_addr = start; } -- cgit v0.10.2 From b5031ed1be0aa419250557123633453753181643 Mon Sep 17 00:00:00 2001 From: Ronny Hegewald Date: Fri, 31 Aug 2012 09:57:52 +0000 Subject: xen: Use correct masking in xen_swiotlb_alloc_coherent. When running 32-bit pvops-dom0 and a driver tries to allocate a coherent DMA-memory the xen swiotlb-implementation returned memory beyond 4GB. The underlaying reason is that if the supplied driver passes in a DMA_BIT_MASK(64) ( hwdev->coherent_dma_mask is set to 0xffffffffffffffff) our dma_mask will be u64 set to 0xffffffffffffffff even if we set it to DMA_BIT_MASK(32) previously. Meaning we do not reset the upper bits. By using the dma_alloc_coherent_mask function - it does the proper casting and we get 0xfffffffff. This caused not working sound on a system with 4 GB and a 64-bit compatible sound-card with sets the DMA-mask to 64bit. On bare-metal and the forward-ported xen-dom0 patches from OpenSuse a coherent DMA-memory is always allocated inside the 32-bit address-range by calling dma_alloc_coherent_mask. This patch adds the same functionality to xen swiotlb and is a rebase of the original patch from Ronny Hegewald which never got upstream b/c the underlaying reason was not understood until now. The original email with the original patch is in: http://old-list-archives.xen.org/archives/html/xen-devel/2010-02/msg00038.html the original thread from where the discussion started is in: http://old-list-archives.xen.org/archives/html/xen-devel/2010-01/msg00928.html Signed-off-by: Ronny Hegewald Signed-off-by: Stefano Panella Acked-By: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk CC: stable@vger.kernel.org diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 1afb4fb..4d51948 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -232,7 +232,7 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, return ret; if (hwdev && hwdev->coherent_dma_mask) - dma_mask = hwdev->coherent_dma_mask; + dma_mask = dma_alloc_coherent_mask(hwdev, flags); phys = virt_to_phys(ret); dev_addr = xen_phys_to_bus(phys); -- cgit v0.10.2 From 1c4c4394a6040b7bd2154e848cd9ab536b6ab0dd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 26 Aug 2012 18:01:01 +0200 Subject: drivers/tty/serial/amba-pl0{10,11}.c: use clk_prepare_enable and clk_disable_unprepare Clk_prepare_enable and clk_disable_unprepare combine clk_prepare and clk_enable, and clk_disable and clk_unprepare. The9 make the code more concise, and ensure that clk_unprepare is called when clk_enable fails. A simplified version of the semantic patch that introduces calls to these functions is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; @@ - clk_prepare(e); - clk_enable(e); + clk_prepare_enable(e); @@ expression e; @@ - clk_disable(e); - clk_unprepare(e); + clk_disable_unprepare(e); // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 0d91a54..22317dd 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -312,16 +312,12 @@ static int pl010_startup(struct uart_port *port) struct uart_amba_port *uap = (struct uart_amba_port *)port; int retval; - retval = clk_prepare(uap->clk); - if (retval) - goto out; - /* * Try to enable the clock producer. */ - retval = clk_enable(uap->clk); + retval = clk_prepare_enable(uap->clk); if (retval) - goto clk_unprep; + goto out; uap->port.uartclk = clk_get_rate(uap->clk); @@ -346,9 +342,7 @@ static int pl010_startup(struct uart_port *port) return 0; clk_dis: - clk_disable(uap->clk); - clk_unprep: - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); out: return retval; } @@ -375,8 +369,7 @@ static void pl010_shutdown(struct uart_port *port) /* * Shut down the clock producer */ - clk_disable(uap->clk); - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); } static void diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 92b1ac8..3322023 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1324,16 +1324,12 @@ static int pl011_startup(struct uart_port *port) "could not set default pins\n"); } - retval = clk_prepare(uap->clk); - if (retval) - goto out; - /* * Try to enable the clock producer. */ - retval = clk_enable(uap->clk); + retval = clk_prepare_enable(uap->clk); if (retval) - goto clk_unprep; + goto out; uap->port.uartclk = clk_get_rate(uap->clk); @@ -1411,9 +1407,7 @@ static int pl011_startup(struct uart_port *port) return 0; clk_dis: - clk_disable(uap->clk); - clk_unprep: - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); out: return retval; } @@ -1473,8 +1467,7 @@ static void pl011_shutdown(struct uart_port *port) /* * Shut down the clock producer */ - clk_disable(uap->clk); - clk_unprepare(uap->clk); + clk_disable_unprepare(uap->clk); /* Optionally let pins go into sleep states */ if (!IS_ERR(uap->pins_sleep)) { retval = pinctrl_select_state(uap->pinctrl, uap->pins_sleep); -- cgit v0.10.2 From c0fc208e487a985c4d083c498fecf791e6e965b7 Mon Sep 17 00:00:00 2001 From: Devendra Naga Date: Fri, 24 Aug 2012 03:34:42 +0530 Subject: tty: max3100: use module_spi_driver the driver's module init and exit functions can be replaced with module_spi_driver as they do only spi_register_driver and spi_unregister_driver in module's init and exit paths. Signed-off-by: Devendra Naga Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index b4902b9..46043c2 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -910,17 +910,7 @@ static struct spi_driver max3100_driver = { .resume = max3100_resume, }; -static int __init max3100_init(void) -{ - return spi_register_driver(&max3100_driver); -} -module_init(max3100_init); - -static void __exit max3100_exit(void) -{ - spi_unregister_driver(&max3100_driver); -} -module_exit(max3100_exit); +module_spi_driver(max3100_driver); MODULE_DESCRIPTION("MAX3100 driver"); MODULE_AUTHOR("Christian Pellegrin "); -- cgit v0.10.2 From 1a16afa2cecd36bc4b6ba00fe4c83fcf5ca6e710 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 20 Aug 2012 15:56:34 +0200 Subject: tty: serial: altera_uart: Use platform_{get,set}_drvdata Use the wrapper functions, so we can directly pass a struct platfrom_device. Signed-off-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 1f03309..15d80b9 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -591,7 +591,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) port->ops = &altera_uart_ops; port->flags = UPF_BOOT_AUTOCONF; - dev_set_drvdata(&pdev->dev, port); + platform_set_drvdata(pdev, port); uart_add_one_port(&altera_uart_driver, port); @@ -600,11 +600,11 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) static int __devexit altera_uart_remove(struct platform_device *pdev) { - struct uart_port *port = dev_get_drvdata(&pdev->dev); + struct uart_port *port = platform_get_drvdata(pdev); if (port) { uart_remove_one_port(&altera_uart_driver, port); - dev_set_drvdata(&pdev->dev, NULL); + platform_set_drvdata(pdev, NULL); port->mapbase = 0; } -- cgit v0.10.2 From 23e7c6a765df64cafebff2d50fc51345797ca99a Mon Sep 17 00:00:00 2001 From: Emil Goode Date: Sat, 18 Aug 2012 18:12:48 +0200 Subject: tty: serial: max310x: Check return code of gpiochip_remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpiochip_remove function may fail to remove a gpio_chip if any GPIOs are still requested. This patch informs the caller of such a senario. Sparse is warning because the function prototype has a __must_check annotation. Sparse warning: drivers/tty/serial/max310x.c:1223:18: warning: ignoring return value of ‘gpiochip_remove’, declared with attribute warn_unused_result [-Wunused-result] Signed-off-by: Emil Goode Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 534e448..06ff5ad 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1207,6 +1207,7 @@ static int __devexit max310x_remove(struct spi_device *spi) { struct device *dev = &spi->dev; struct max310x_port *s = dev_get_drvdata(dev); + int ret = 0; dev_dbg(dev, "Removing port\n"); @@ -1219,8 +1220,11 @@ static int __devexit max310x_remove(struct spi_device *spi) uart_unregister_driver(&s->uart); #ifdef CONFIG_GPIOLIB - if (s->pdata->gpio_base) - gpiochip_remove(&s->gpio); + if (s->pdata->gpio_base) { + ret = gpiochip_remove(&s->gpio); + if (ret) + dev_err(dev, "Failed to remove gpio chip: %d\n", ret); + } #endif dev_set_drvdata(dev, NULL); @@ -1232,7 +1236,7 @@ static int __devexit max310x_remove(struct spi_device *spi) devm_kfree(dev, s); - return 0; + return ret; } static const struct spi_device_id max310x_id_table[] = { -- cgit v0.10.2 From fd7c81f864e3d8a2847fc0e36fde78b0da2fdf2c Mon Sep 17 00:00:00 2001 From: Emil Goode Date: Sat, 18 Aug 2012 18:12:49 +0200 Subject: tty: serial: max310x: Remove explicit use of devm_kfree There is no reason to explicitly call devm_kfree in probe or remove functions. Signed-off-by: Emil Goode Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 06ff5ad..2bc28a5 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1198,7 +1198,6 @@ err_freq: err_out: dev_set_drvdata(dev, NULL); - devm_kfree(dev, s); return ret; } @@ -1234,8 +1233,6 @@ static int __devexit max310x_remove(struct spi_device *spi) if (s->pdata->exit) s->pdata->exit(); - devm_kfree(dev, s); - return ret; } -- cgit v0.10.2 From bbb63c514a3464342967237a51a21ea8f61ab951 Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Mon, 27 Aug 2012 15:23:12 +0800 Subject: drivers:tty:fix up ENOIOCTLCMD error handling At commit 07d106d0, Linus pointed out that ENOIOCTLCMD should be translated as ENOTTY to user mode. For example: fd = open("/dev/tty", O_RDWR); ioctl(fd, -1, &argp); then the errno should be ENOTTY but not EINVAL. Signed-off-by: Wanlong Gao Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 41e42f1..d3bf91a 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2774,7 +2774,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (ld->ops->ioctl) { retval = ld->ops->ioctl(tty, file, cmd, arg); if (retval == -ENOIOCTLCMD) - retval = -EINVAL; + retval = -ENOTTY; } tty_ldisc_deref(ld); return retval; -- cgit v0.10.2 From d3dec96e401cc66d7280732558d711ac2ee7a531 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 27 Aug 2012 16:03:14 +0200 Subject: tty: serial: mpc5xxx: add support for mark/space parity Tested on a custom MPC5200B-board using some fancy industrial protocol. Verified that MPC512x has identical bits, so should work there as well. Signed-off-by: Wolfram Sang Acked-by: Anatolij Gustschin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index bedac0d..f19d04e 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -775,11 +775,15 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, } if (new->c_cflag & PARENB) { + if (new->c_cflag & CMSPAR) + mr1 |= MPC52xx_PSC_MODE_PARFORCE; + + /* With CMSPAR, PARODD also means high parity (same as termios) */ mr1 |= (new->c_cflag & PARODD) ? MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN; - } else + } else { mr1 |= MPC52xx_PSC_MODE_PARNONE; - + } mr2 = 0; -- cgit v0.10.2 From 9250dd5738ca2f2728913fefc6573daf5b95efa4 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Sep 2012 18:33:09 +0200 Subject: drivers/tty/serial/sirfsoc_uart.c: drop frees of devm_ alloc'd data devm free functions should not have to be explicitly used. A semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ @@ ( * devm_kfree(...); | * devm_free_irq(...); | * devm_iounmap(...); | * devm_release_region(...); | * devm_release_mem_region(...); ) // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 5b3eda2..a9e2bd1 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -668,7 +668,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "Insufficient resources.\n"); ret = -EFAULT; - goto irq_err; + goto err; } port->irq = res->start; @@ -676,7 +676,7 @@ int sirfsoc_uart_probe(struct platform_device *pdev) sirfport->p = pinctrl_get_select_default(&pdev->dev); ret = IS_ERR(sirfport->p); if (ret) - goto pin_err; + goto err; } port->ops = &sirfsoc_uart_ops; @@ -695,9 +695,6 @@ port_err: platform_set_drvdata(pdev, NULL); if (sirfport->hw_flow_ctrl) pinctrl_put(sirfport->p); -pin_err: -irq_err: - devm_iounmap(&pdev->dev, port->membase); err: return ret; } @@ -709,7 +706,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (sirfport->hw_flow_ctrl) pinctrl_put(sirfport->p); - devm_iounmap(&pdev->dev, port->membase); uart_remove_one_port(&sirfsoc_uart_drv, port); return 0; } -- cgit v0.10.2 From 7ba2e769825fef035a943ed74d90379245508764 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Sep 2012 16:34:45 +0100 Subject: tty: Split the serial_core helpers for setserial into two We want them split so that we can call them from setserial functionality where we copy to/from user space and do the locking, but also from sysfs where in future we'll want to came them within a sysfs context. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 5b308c8..bb5f236 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -634,38 +634,44 @@ static void uart_unthrottle(struct tty_struct *tty) uart_set_mctrl(port, TIOCM_RTS); } -static int uart_get_info(struct uart_state *state, - struct serial_struct __user *retinfo) +static void uart_get_info(struct tty_port *port, + struct uart_state *state, + struct serial_struct *retinfo) { struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - /* Ensure the state we copy is consistent and no hardware changes - occur as we go */ - mutex_lock(&port->mutex); + memset(retinfo, 0, sizeof(retinfo)); - tmp.type = uport->type; - tmp.line = uport->line; - tmp.port = uport->iobase; + retinfo->type = uport->type; + retinfo->line = uport->line; + retinfo->port = uport->iobase; if (HIGH_BITS_OFFSET) - tmp.port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; - tmp.irq = uport->irq; - tmp.flags = uport->flags; - tmp.xmit_fifo_size = uport->fifosize; - tmp.baud_base = uport->uartclk / 16; - tmp.close_delay = jiffies_to_msecs(port->close_delay) / 10; - tmp.closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? + retinfo->port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; + retinfo->irq = uport->irq; + retinfo->flags = uport->flags; + retinfo->xmit_fifo_size = uport->fifosize; + retinfo->baud_base = uport->uartclk / 16; + retinfo->close_delay = jiffies_to_msecs(port->close_delay) / 10; + retinfo->closing_wait = port->closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : jiffies_to_msecs(port->closing_wait) / 10; - tmp.custom_divisor = uport->custom_divisor; - tmp.hub6 = uport->hub6; - tmp.io_type = uport->iotype; - tmp.iomem_reg_shift = uport->regshift; - tmp.iomem_base = (void *)(unsigned long)uport->mapbase; + retinfo->custom_divisor = uport->custom_divisor; + retinfo->hub6 = uport->hub6; + retinfo->io_type = uport->iotype; + retinfo->iomem_reg_shift = uport->regshift; + retinfo->iomem_base = (void *)(unsigned long)uport->mapbase; +} + +static int uart_get_info_user(struct uart_state *state, + struct serial_struct __user *retinfo) +{ + struct tty_port *port = &state->port; + struct serial_struct tmp; + /* Ensure the state we copy is consistent and no hardware changes + occur as we go */ + mutex_lock(&port->mutex); + uart_get_info(port, state, &tmp); mutex_unlock(&port->mutex); if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) @@ -673,42 +679,30 @@ static int uart_get_info(struct uart_state *state, return 0; } -static int uart_set_info(struct tty_struct *tty, struct uart_state *state, - struct serial_struct __user *newinfo) +static int uart_set_info(struct tty_struct *tty, struct tty_port *port, + struct uart_state *state, + struct serial_struct *new_info) { - struct serial_struct new_serial; struct uart_port *uport = state->uart_port; - struct tty_port *port = &state->port; unsigned long new_port; unsigned int change_irq, change_port, closing_wait; unsigned int old_custom_divisor, close_delay; upf_t old_flags, new_flags; int retval = 0; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - new_port = new_serial.port; + new_port = new_info->port; if (HIGH_BITS_OFFSET) - new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET; - new_serial.irq = irq_canonicalize(new_serial.irq); - close_delay = msecs_to_jiffies(new_serial.close_delay * 10); - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + new_info->irq = irq_canonicalize(new_info->irq); + close_delay = msecs_to_jiffies(new_info->close_delay * 10); + closing_wait = new_info->closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - msecs_to_jiffies(new_serial.closing_wait * 10); + msecs_to_jiffies(new_info->closing_wait * 10); - /* - * This semaphore protects port->count. It is also - * very useful to prevent opens. Also, take the - * port configuration semaphore to make sure that a - * module insertion/removal doesn't change anything - * under us. - */ - mutex_lock(&port->mutex); change_irq = !(uport->flags & UPF_FIXED_PORT) - && new_serial.irq != uport->irq; + && new_info->irq != uport->irq; /* * Since changing the 'type' of the port changes its resource @@ -717,29 +711,29 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, */ change_port = !(uport->flags & UPF_FIXED_PORT) && (new_port != uport->iobase || - (unsigned long)new_serial.iomem_base != uport->mapbase || - new_serial.hub6 != uport->hub6 || - new_serial.io_type != uport->iotype || - new_serial.iomem_reg_shift != uport->regshift || - new_serial.type != uport->type); + (unsigned long)new_info->iomem_base != uport->mapbase || + new_info->hub6 != uport->hub6 || + new_info->io_type != uport->iotype || + new_info->iomem_reg_shift != uport->regshift || + new_info->type != uport->type); old_flags = uport->flags; - new_flags = new_serial.flags; + new_flags = new_info->flags; old_custom_divisor = uport->custom_divisor; if (!capable(CAP_SYS_ADMIN)) { retval = -EPERM; if (change_irq || change_port || - (new_serial.baud_base != uport->uartclk / 16) || + (new_info->baud_base != uport->uartclk / 16) || (close_delay != port->close_delay) || (closing_wait != port->closing_wait) || - (new_serial.xmit_fifo_size && - new_serial.xmit_fifo_size != uport->fifosize) || + (new_info->xmit_fifo_size && + new_info->xmit_fifo_size != uport->fifosize) || (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) goto exit; uport->flags = ((uport->flags & ~UPF_USR_MASK) | (new_flags & UPF_USR_MASK)); - uport->custom_divisor = new_serial.custom_divisor; + uport->custom_divisor = new_info->custom_divisor; goto check_and_exit; } @@ -747,10 +741,10 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, * Ask the low level driver to verify the settings. */ if (uport->ops->verify_port) - retval = uport->ops->verify_port(uport, &new_serial); + retval = uport->ops->verify_port(uport, new_info); - if ((new_serial.irq >= nr_irqs) || (new_serial.irq < 0) || - (new_serial.baud_base < 9600)) + if ((new_info->irq >= nr_irqs) || (new_info->irq < 0) || + (new_info->baud_base < 9600)) retval = -EINVAL; if (retval) @@ -790,11 +784,11 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, uport->ops->release_port(uport); uport->iobase = new_port; - uport->type = new_serial.type; - uport->hub6 = new_serial.hub6; - uport->iotype = new_serial.io_type; - uport->regshift = new_serial.iomem_reg_shift; - uport->mapbase = (unsigned long)new_serial.iomem_base; + uport->type = new_info->type; + uport->hub6 = new_info->hub6; + uport->iotype = new_info->io_type; + uport->regshift = new_info->iomem_reg_shift; + uport->mapbase = (unsigned long)new_info->iomem_base; /* * Claim and map the new regions @@ -835,16 +829,16 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, } if (change_irq) - uport->irq = new_serial.irq; + uport->irq = new_info->irq; if (!(uport->flags & UPF_FIXED_PORT)) - uport->uartclk = new_serial.baud_base * 16; + uport->uartclk = new_info->baud_base * 16; uport->flags = (uport->flags & ~UPF_CHANGE_MASK) | (new_flags & UPF_CHANGE_MASK); - uport->custom_divisor = new_serial.custom_divisor; + uport->custom_divisor = new_info->custom_divisor; port->close_delay = close_delay; port->closing_wait = closing_wait; - if (new_serial.xmit_fifo_size) - uport->fifosize = new_serial.xmit_fifo_size; + if (new_info->xmit_fifo_size) + uport->fifosize = new_info->xmit_fifo_size; if (port->tty) port->tty->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; @@ -873,6 +867,28 @@ static int uart_set_info(struct tty_struct *tty, struct uart_state *state, } else retval = uart_startup(tty, state, 1); exit: + return retval; +} + +static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, + struct serial_struct __user *newinfo) +{ + struct serial_struct new_serial; + struct tty_port *port = &state->port; + int retval; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + /* + * This semaphore protects port->count. It is also + * very useful to prevent opens. Also, take the + * port configuration semaphore to make sure that a + * module insertion/removal doesn't change anything + * under us. + */ + mutex_lock(&port->mutex); + retval = uart_set_info(tty, port, state, &new_serial); mutex_unlock(&port->mutex); return retval; } @@ -1115,11 +1131,11 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, */ switch (cmd) { case TIOCGSERIAL: - ret = uart_get_info(state, uarg); + ret = uart_get_info_user(state, uarg); break; case TIOCSSERIAL: - ret = uart_set_info(tty, state, uarg); + ret = uart_set_info_user(tty, state, uarg); break; case TIOCSERCONFIG: -- cgit v0.10.2 From ba3fe7aba2067212a8c3baffc18f9209fcbe9d34 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Sep 2012 16:35:08 +0100 Subject: tty: move the async flags from the serial code into the tty includes These are used with the tty_port flags which are tty generic so move the flags into a more sensible place. This then makes it possible to add helpers such as those suggested by Huang Shijie. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/Kbuild b/include/linux/Kbuild index e9f560a..c57e064 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -369,6 +369,7 @@ header-y += tipc.h header-y += tipc_config.h header-y += toshiba.h header-y += tty.h +header-y += tty_flags.h header-y += types.h header-y += udf_fs_i.h header-y += udp.h diff --git a/include/linux/serial.h b/include/linux/serial.h index 90e9f98..3504f42 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -12,9 +12,12 @@ #include +#include + #ifdef __KERNEL__ #include + /* * Counters of the input lines (CTS, DSR, RI, CD) interrupts */ @@ -94,78 +97,6 @@ struct serial_uart_config { #define UART_STARTECH 0x04 #define UART_NATSEMI 0x08 -/* - * Definitions for async_struct (and serial_struct) flags field - * - * Define ASYNCB_* for convenient use with {test,set,clear}_bit. - */ -#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes - * on the callout port */ -#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */ -#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */ -#define ASYNCB_SPLIT_TERMIOS 3 /* Separate termios for dialin/callout */ -#define ASYNCB_SPD_HI 4 /* Use 56000 instead of 38400 bps */ -#define ASYNCB_SPD_VHI 5 /* Use 115200 instead of 38400 bps */ -#define ASYNCB_SKIP_TEST 6 /* Skip UART test during autoconfiguration */ -#define ASYNCB_AUTO_IRQ 7 /* Do automatic IRQ during - * autoconfiguration */ -#define ASYNCB_SESSION_LOCKOUT 8 /* Lock out cua opens based on session */ -#define ASYNCB_PGRP_LOCKOUT 9 /* Lock out cua opens based on pgrp */ -#define ASYNCB_CALLOUT_NOHUP 10 /* Don't do hangups for cua device */ -#define ASYNCB_HARDPPS_CD 11 /* Call hardpps when CD goes high */ -#define ASYNCB_SPD_SHI 12 /* Use 230400 instead of 38400 bps */ -#define ASYNCB_LOW_LATENCY 13 /* Request low latency behaviour */ -#define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety - * checks. Note: can be dangerous! */ -#define ASYNCB_AUTOPROBE 15 /* Port was autoprobed by PCI or PNP code */ -#define ASYNCB_LAST_USER 15 - -/* Internal flags used only by kernel */ -#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ -#define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ -#define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ -#define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */ -#define ASYNCB_CLOSING 27 /* Serial port is closing */ -#define ASYNCB_CTS_FLOW 26 /* Do CTS flow control */ -#define ASYNCB_CHECK_CD 25 /* i.e., CLOCAL */ -#define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */ -#define ASYNCB_CONS_FLOW 23 /* flow control for console */ -#define ASYNCB_FIRST_KERNEL 22 - -#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) -#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED) -#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT) -#define ASYNC_SAK (1U << ASYNCB_SAK) -#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS) -#define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI) -#define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI) -#define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST) -#define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ) -#define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT) -#define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT) -#define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP) -#define ASYNC_HARDPPS_CD (1U << ASYNCB_HARDPPS_CD) -#define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI) -#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY) -#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART) -#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE) - -#define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1) -#define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \ - ASYNC_LOW_LATENCY) -#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI) -#define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) -#define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) - -#define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED) -#define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE) -#define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF) -#define ASYNC_CLOSING (1U << ASYNCB_CLOSING) -#define ASYNC_CTS_FLOW (1U << ASYNCB_CTS_FLOW) -#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD) -#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ) -#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW) -#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1)) /* * Multiport serial configuration structure --- external structure diff --git a/include/linux/tty.h b/include/linux/tty.h index 69a787f..dbebd1e 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -43,6 +43,7 @@ #include #include #include +#include diff --git a/include/linux/tty_flags.h b/include/linux/tty_flags.h new file mode 100644 index 0000000..eefcb48 --- /dev/null +++ b/include/linux/tty_flags.h @@ -0,0 +1,78 @@ +#ifndef _LINUX_TTY_FLAGS_H +#define _LINUX_TTY_FLAGS_H + +/* + * Definitions for async_struct (and serial_struct) flags field also + * shared by the tty_port flags structures. + * + * Define ASYNCB_* for convenient use with {test,set,clear}_bit. + */ +#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes + * on the callout port */ +#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */ +#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */ +#define ASYNCB_SPLIT_TERMIOS 3 /* Separate termios for dialin/callout */ +#define ASYNCB_SPD_HI 4 /* Use 56000 instead of 38400 bps */ +#define ASYNCB_SPD_VHI 5 /* Use 115200 instead of 38400 bps */ +#define ASYNCB_SKIP_TEST 6 /* Skip UART test during autoconfiguration */ +#define ASYNCB_AUTO_IRQ 7 /* Do automatic IRQ during + * autoconfiguration */ +#define ASYNCB_SESSION_LOCKOUT 8 /* Lock out cua opens based on session */ +#define ASYNCB_PGRP_LOCKOUT 9 /* Lock out cua opens based on pgrp */ +#define ASYNCB_CALLOUT_NOHUP 10 /* Don't do hangups for cua device */ +#define ASYNCB_HARDPPS_CD 11 /* Call hardpps when CD goes high */ +#define ASYNCB_SPD_SHI 12 /* Use 230400 instead of 38400 bps */ +#define ASYNCB_LOW_LATENCY 13 /* Request low latency behaviour */ +#define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety + * checks. Note: can be dangerous! */ +#define ASYNCB_AUTOPROBE 15 /* Port was autoprobed by PCI or PNP code */ +#define ASYNCB_LAST_USER 15 + +/* Internal flags used only by kernel */ +#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ +#define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ +#define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ +#define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */ +#define ASYNCB_CLOSING 27 /* Serial port is closing */ +#define ASYNCB_CTS_FLOW 26 /* Do CTS flow control */ +#define ASYNCB_CHECK_CD 25 /* i.e., CLOCAL */ +#define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */ +#define ASYNCB_CONS_FLOW 23 /* flow control for console */ +#define ASYNCB_FIRST_KERNEL 22 + +#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) +#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED) +#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT) +#define ASYNC_SAK (1U << ASYNCB_SAK) +#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS) +#define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI) +#define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI) +#define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST) +#define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ) +#define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT) +#define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT) +#define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP) +#define ASYNC_HARDPPS_CD (1U << ASYNCB_HARDPPS_CD) +#define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI) +#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY) +#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART) +#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE) + +#define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1) +#define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \ + ASYNC_LOW_LATENCY) +#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI) +#define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) +#define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) + +#define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED) +#define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE) +#define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF) +#define ASYNC_CLOSING (1U << ASYNCB_CLOSING) +#define ASYNC_CTS_FLOW (1U << ASYNCB_CTS_FLOW) +#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD) +#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ) +#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW) +#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1)) + +#endif -- cgit v0.10.2 From 833462e94cf091ef11f34219ca92d093ff9d2c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 20 Aug 2012 09:57:04 +0200 Subject: serial/imx: improve error diagnosics for clock and pinctrl failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These error paths are used more often now after deep changes to the clock code and pinctrl is still new for imx. So help debugging and give clues in the boot log. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 20e9117..72ec56e 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1505,18 +1505,21 @@ static int serial_imx_probe(struct platform_device *pdev) pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) { ret = PTR_ERR(pinctrl); + dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret); goto unmap; } sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk_ipg)) { ret = PTR_ERR(sport->clk_ipg); + dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret); goto unmap; } sport->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(sport->clk_per)) { ret = PTR_ERR(sport->clk_per); + dev_err(&pdev->dev, "failed to get per clk: %d\n", ret); goto unmap; } -- cgit v0.10.2 From b8ede90cce2c63c5c592acb5d756cc14fcac448a Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Aug 2012 19:56:26 -0400 Subject: m32r_sio: remove dependency on struct serial_uart_config The struct serial_uart_config is hardly used at all, and the use case like this one are somewhat needless. Remove the trivial usage so that we can remove serial_uart_config. Since the type field isn't really used at all, we also delete the initialization and references of it here as well. Cc: Hirokazu Takata Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index a070362..b13949a 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -44,8 +44,6 @@ #include #include -#define PORT_M32R_BASE PORT_M32R_SIO -#define PORT_INDEX(x) (x - PORT_M32R_BASE + 1) #define BAUD_RATE 115200 #include @@ -132,22 +130,6 @@ struct irq_info { static struct irq_info irq_lists[NR_IRQS]; -/* - * Here we define the default xmit fifo size used for each type of UART. - */ -static const struct serial_uart_config uart_config[] = { - [PORT_UNKNOWN] = { - .name = "unknown", - .dfl_xmit_fifo_size = 1, - .flags = 0, - }, - [PORT_INDEX(PORT_M32R_SIO)] = { - .name = "M32RSIO", - .dfl_xmit_fifo_size = 1, - .flags = 0, - }, -}; - #ifdef CONFIG_SERIAL_M32R_PLDSIO #define __sio_in(x) inw((unsigned long)(x)) @@ -907,8 +889,7 @@ static void m32r_sio_config_port(struct uart_port *port, int unused) spin_lock_irqsave(&up->port.lock, flags); - up->port.type = (PORT_M32R_SIO - PORT_M32R_BASE + 1); - up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; + up->port.fifosize = 1; spin_unlock_irqrestore(&up->port.lock, flags); } @@ -916,23 +897,11 @@ static void m32r_sio_config_port(struct uart_port *port, int unused) static int m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser) { - if (ser->irq >= nr_irqs || ser->irq < 0 || - ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || - ser->type >= ARRAY_SIZE(uart_config)) + if (ser->irq >= nr_irqs || ser->irq < 0 || ser->baud_base < 9600) return -EINVAL; return 0; } -static const char * -m32r_sio_type(struct uart_port *port) -{ - int type = port->type; - - if (type >= ARRAY_SIZE(uart_config)) - type = 0; - return uart_config[type].name; -} - static struct uart_ops m32r_sio_pops = { .tx_empty = m32r_sio_tx_empty, .set_mctrl = m32r_sio_set_mctrl, @@ -946,7 +915,6 @@ static struct uart_ops m32r_sio_pops = { .shutdown = m32r_sio_shutdown, .set_termios = m32r_sio_set_termios, .pm = m32r_sio_pm, - .type = m32r_sio_type, .release_port = m32r_sio_release_port, .request_port = m32r_sio_request_port, .config_port = m32r_sio_config_port, -- cgit v0.10.2 From e2c654254e3379f69ce4a2e3f322374dd071337d Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Aug 2012 19:56:27 -0400 Subject: serial: sunsu.c - don't explicitly tie array size to dynamic entity The addition of 8250-like entities continues to grow, while this driver has a snapshot of a select few common 8250 UARTs. So it has no need to grow with the new additions, since it calls out its own (largely historic) static list which does not grow. Cc: "David S. Miller" Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 675303b..d919095 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -61,7 +61,7 @@ static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" }; /* * Here we define the default xmit fifo size used for each type of UART. */ -static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { +static const struct serial_uart_config uart_config[] = { { "unknown", 1, 0 }, { "8250", 1, 0 }, { "16450", 1, 0 }, -- cgit v0.10.2 From 4b71598b6a1e72d11a657ccd67bdb14f1c269186 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 20 Aug 2012 19:56:28 -0400 Subject: serial: diminish usage of struct serial_uart_config This structure might have made sense many years ago, but at this point it is only used in one specific driver, and referenced in stale comments elsewhere. Rather than change the sunsu.c driver, simply move the struct to be within the exclusive domain of that driver, so it won't get inadvertently picked up and used by other serial drivers going forward. The comments referencing the now driver specific struct are updated accordingly. Note that 8250.c has a struct that is similar in usage, with the name serial8250_config; but is 100% independent and untouched here. Cc: "David S. Miller" Signed-off-by: Paul Gortmaker Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h index 614271f..55d68b5 100644 --- a/drivers/staging/speakup/serialio.h +++ b/drivers/staging/speakup/serialio.h @@ -1,8 +1,7 @@ #ifndef _SPEAKUP_SERIAL_H #define _SPEAKUP_SERIAL_H -#include /* for rs_table, serial constants & - serial_uart_config */ +#include /* for rs_table, serial constants */ #include /* for more serial constants */ #ifndef __sparc__ #include diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 972b521..0c5e908 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -26,9 +26,6 @@ struct old_serial_port { unsigned long irqflags; }; -/* - * This replaces serial_uart_config in include/linux/serial.h - */ struct serial8250_config { const char *name; unsigned short fifo_size; diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index d919095..b97913d 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -58,6 +58,12 @@ enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT }; static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" }; +struct serial_uart_config { + char *name; + int dfl_xmit_fifo_size; + int flags; +}; + /* * Here we define the default xmit fifo size used for each type of UART. */ diff --git a/include/linux/serial.h b/include/linux/serial.h index 3504f42..861e51d 100644 --- a/include/linux/serial.h +++ b/include/linux/serial.h @@ -86,12 +86,6 @@ struct serial_struct { #define SERIAL_IO_HUB6 1 #define SERIAL_IO_MEM 2 -struct serial_uart_config { - char *name; - int dfl_xmit_fifo_size; - int flags; -}; - #define UART_CLEAR_FIFO 0x01 #define UART_USE_FIFO 0x02 #define UART_STARTECH 0x04 -- cgit v0.10.2 From 32614aad30549b0e4caf44c26efe8e2b09d597ce Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Tue, 28 Aug 2012 16:41:28 +0100 Subject: serial: pl011: honour serial aliases in device tree If the order of UART nodes is changed in the device tree, then tty dev devices are attached to different serial ports causing the console to be directed to a different physical serial port. The "serial" aliases in the device tree should prevent this. This patch ensures that the UART driver creates tty devices that honour these aliases if a device tree is present. Acked-by: Linus Walleij Reviewed-by: Will Deacon Acked-by: Rob Herring Signed-off-by: Matthew Leach Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 3322023..05c15ec 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include @@ -1862,6 +1864,38 @@ static struct uart_driver amba_reg = { .cons = AMBA_CONSOLE, }; +static int pl011_probe_dt_alias(int index, struct device *dev) +{ + struct device_node *np; + static bool seen_dev_with_alias = false; + static bool seen_dev_without_alias = false; + int ret = index; + + if (!IS_ENABLED(CONFIG_OF)) + return ret; + + np = dev->of_node; + if (!np) + return ret; + + ret = of_alias_get_id(np, "serial"); + if (IS_ERR_VALUE(ret)) { + seen_dev_without_alias = true; + ret = index; + } else { + seen_dev_with_alias = true; + if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) { + dev_warn(dev, "requested serial port %d not available.\n", ret); + ret = index; + } + } + + if (seen_dev_with_alias && seen_dev_without_alias) + dev_warn(dev, "aliased and non-aliased serial devices found in device tree. Serial port enumeration may be unpredictable.\n"); + + return ret; +} + static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; @@ -1884,6 +1918,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) goto out; } + i = pl011_probe_dt_alias(i, &dev->dev); + base = ioremap(dev->res.start, resource_size(&dev->res)); if (!base) { ret = -ENOMEM; -- cgit v0.10.2 From d20925e1e4fbd501754efad5401040d700fae4d6 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 5 Sep 2012 10:30:10 +0530 Subject: serial: Samsung: Replace printk with dev_* functions Silences checkpatch warnings regarding use of printks. Signed-off-by: Sachin Kamat Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 5c5e7e0..8749a07 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -459,7 +459,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) s3c24xx_serial_portname(port), ourport); if (ret != 0) { - printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq); + dev_err(port->dev, "cannot get irq %d\n", ourport->rx_irq); return ret; } @@ -473,7 +473,7 @@ static int s3c24xx_serial_startup(struct uart_port *port) s3c24xx_serial_portname(port), ourport); if (ret) { - printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq); + dev_err(port->dev, "cannot get irq %d\n", ourport->tx_irq); goto err; } @@ -502,7 +502,7 @@ static int s3c64xx_serial_startup(struct uart_port *port) ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED, s3c24xx_serial_portname(port), ourport); if (ret) { - printk(KERN_ERR "cannot get irq %d\n", port->irq); + dev_err(port->dev, "cannot get irq %d\n", port->irq); return ret; } @@ -543,7 +543,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, break; default: - printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level); + dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level); } } @@ -1038,7 +1038,7 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, termios = &tty->termios; if (termios == NULL) { - printk(KERN_WARNING "%s: no termios?\n", __func__); + dev_warn(uport->dev, "%s: no termios?\n", __func__); goto exit; } @@ -1113,7 +1113,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, res = platform_get_resource(platdev, IORESOURCE_MEM, 0); if (res == NULL) { - printk(KERN_ERR "failed to find memory resource for uart\n"); + dev_err(port->dev, "failed to find memory resource for uart\n"); return -EINVAL; } @@ -1683,7 +1683,7 @@ static int __init s3c24xx_serial_modinit(void) ret = uart_register_driver(&s3c24xx_uart_drv); if (ret < 0) { - printk(KERN_ERR "failed to register UART driver\n"); + pr_err("Failed to register Samsung UART driver\n"); return -1; } -- cgit v0.10.2 From 9303ac158fcd5f69c032e06391a9a12d3ccb343e Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 5 Sep 2012 10:30:11 +0530 Subject: serial: Samsung: Silence some checkpatch errors and warnings Fixes the following errors and warnings: ERROR: trailing whitespace ERROR: return is not a function, parentheses are not required WARNING: suspect code indent for conditional statements (32, 36) Signed-off-by: Sachin Kamat Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 8749a07..bdaa06f 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -82,7 +82,7 @@ static inline const char *s3c24xx_serial_portname(struct uart_port *port) static int s3c24xx_serial_txempty_nofifo(struct uart_port *port) { - return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE); + return rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE; } /* @@ -268,7 +268,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id) dbg("break!\n"); port->icount.brk++; if (uart_handle_break(port)) - goto ignore_char; + goto ignore_char; } if (uerstat & S3C2410_UERSTAT_FRAME) @@ -1129,7 +1129,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, ourport->rx_irq = ret; ourport->tx_irq = ret + 1; } - + ret = platform_get_irq(platdev, 1); if (ret > 0) ourport->tx_irq = ret; -- cgit v0.10.2 From 6971c635af27b1d18d409e337e70bae25d2fa8ec Mon Sep 17 00:00:00 2001 From: Guainluca Anzolin Date: Tue, 4 Sep 2012 15:56:12 +0100 Subject: parport_serial: Add support for the WCH353 2S/1P multi-IO card To allow parport_serial to handle the card the same PCI ids are blacklisted in 8250_pci.c using the existing software blacklist mechanism. The blacklist array is also renamed because it now covers this new use case. Since the two serial ports are auto-detected as XScale instead of 16550A clones, we also add a quirk to 8250_pci.c to skip autodetection and set the correct port type. Signed-off-by: Gianluca Anzolin [Fold in fixes for the uart_8250 change] Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index e9c3227..1631eea 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -62,6 +62,7 @@ enum parport_pc_pci_cards { timedia_9079a, timedia_9079b, timedia_9079c, + wch_ch353_2s1p, }; /* each element directly indexed from enum list, above */ @@ -145,6 +146,7 @@ static struct parport_pc_pci cards[] __devinitdata = { /* timedia_9079a */ { 1, { { 2, 3 }, } }, /* timedia_9079b */ { 1, { { 2, 3 }, } }, /* timedia_9079c */ { 1, { { 2, 3 }, } }, + /* wch_ch353_2s1p*/ { 1, { { 2, -1}, } }, }; static struct pci_device_id parport_serial_pci_tbl[] = { @@ -243,7 +245,8 @@ static struct pci_device_id parport_serial_pci_tbl[] = { { 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a }, { 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b }, { 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c }, - + /* WCH CARDS */ + { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p}, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); @@ -460,6 +463,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { .base_baud = 921600, .uart_offset = 8, }, + [wch_ch353_2s1p] = { + .flags = FL_BASE0|FL_BASE_BARS, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + }, }; struct parport_serial_private { diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index ad4bb8d..803d313 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1164,6 +1164,16 @@ pci_xr17c154_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int +pci_wch_ch353_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + port->port.flags |= UPF_FIXED_TYPE; + port->port.type = PORT_16550A; + return pci_default_setup(priv, board, port, idx); +} + #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1737,6 +1747,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_omegapci_setup, }, + /* WCH CH353 2S1P card (16550 clone) */ + { + .vendor = 0x4348, + .device = 0x7053, + .subvendor = 0x4348, + .subdevice = 0x3253, + .setup = pci_wch_ch353_setup, + }, /* * ASIX devices with FIFO bug */ @@ -2636,10 +2654,14 @@ static struct pciserial_board pci_boards[] __devinitdata = { }, }; -static const struct pci_device_id softmodem_blacklist[] = { +static const struct pci_device_id blacklist[] = { + /* softmodems */ { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */ { PCI_VDEVICE(MOTOROLA, 0x3052), }, /* Motorola Si3052-based modem */ { PCI_DEVICE(0x1543, 0x3052), }, /* Si3052-based modem, default IDs */ + + /* multi-io cards handled by parport_serial */ + { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ }; /* @@ -2650,7 +2672,7 @@ static const struct pci_device_id softmodem_blacklist[] = { static int __devinit serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { - const struct pci_device_id *blacklist; + const struct pci_device_id *bldev; int num_iomem, num_port, first_port = -1, i; /* @@ -2667,13 +2689,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) /* * Do not access blacklisted devices that are known not to - * feature serial ports. + * feature serial ports or are handled by other modules. */ - for (blacklist = softmodem_blacklist; - blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist); - blacklist++) { - if (dev->vendor == blacklist->vendor && - dev->device == blacklist->device) + for (bldev = blacklist; + bldev < blacklist + ARRAY_SIZE(blacklist); + bldev++) { + if (dev->vendor == bldev->vendor && + dev->device == bldev->device) return -ENODEV; } -- cgit v0.10.2 From 1d65c0b12656d9f3bc29bb19f2d7441832433f03 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 25 Aug 2012 19:24:19 +0400 Subject: serial: New serial driver SCCNXP This driver is a replacement for a SC26XX driver with a lot of improvements and new features. The main differences from the SC26XX driver: - Removed dependency on MIPS. Driver can be used on any platform. - Added support for SCC2681, SCC2691, SCC2692, SC28L91, SC28L92, SC28L202, SCC68681 and SCC68692 ICs. - Using devm_-related functions. - Improved error handling of serial port, improved FIFO handling. - Ability to load multiple instances of drivers. To avoid the possibility of regression, driver SC26XX left in the system to confirm the stability of the driver on platforms where it is being used. Signed-off-by: Alexander Shiyan Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 04b9e13..26907cf 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1130,6 +1130,24 @@ config SERIAL_SC26XX_CONSOLE help Support for Console on SC2681/SC2692 serial ports. +config SERIAL_SCCNXP + bool "SCCNXP serial port support" + depends on !SERIAL_SC26XX + select SERIAL_CORE + default n + help + This selects support for an advanced UART from NXP (Philips). + Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92, + SC28L202, SCC68681 and SCC68692. + Positioned as a replacement for the driver SC26XX. + +config SERIAL_SCCNXP_CONSOLE + bool "Console on SCCNXP serial port" + depends on SERIAL_SCCNXP + select SERIAL_CORE_CONSOLE + help + Support for console on SCCNXP serial ports. + config SERIAL_BFIN_SPORT tristate "Blackfin SPORT emulate UART" depends on BLACKFIN diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 2af9e52..ce88667 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o +obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c new file mode 100644 index 0000000..29dda9b --- /dev/null +++ b/drivers/tty/serial/sccnxp.c @@ -0,0 +1,985 @@ +/* + * NXP (Philips) SCC+++(SCN+++) serial driver + * + * Copyright (C) 2012 Alexander Shiyan + * + * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#if defined(CONFIG_SERIAL_SCCNXP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCCNXP_NAME "uart-sccnxp" +#define SCCNXP_MAJOR 204 +#define SCCNXP_MINOR 205 + +#define SCCNXP_MR_REG (0x00) +# define MR0_BAUD_NORMAL (0 << 0) +# define MR0_BAUD_EXT1 (1 << 0) +# define MR0_BAUD_EXT2 (5 << 0) +# define MR0_FIFO (1 << 3) +# define MR0_TXLVL (1 << 4) +# define MR1_BITS_5 (0 << 0) +# define MR1_BITS_6 (1 << 0) +# define MR1_BITS_7 (2 << 0) +# define MR1_BITS_8 (3 << 0) +# define MR1_PAR_EVN (0 << 2) +# define MR1_PAR_ODD (1 << 2) +# define MR1_PAR_NO (4 << 2) +# define MR2_STOP1 (7 << 0) +# define MR2_STOP2 (0xf << 0) +#define SCCNXP_SR_REG (0x01) +#define SCCNXP_CSR_REG SCCNXP_SR_REG +# define SR_RXRDY (1 << 0) +# define SR_FULL (1 << 1) +# define SR_TXRDY (1 << 2) +# define SR_TXEMT (1 << 3) +# define SR_OVR (1 << 4) +# define SR_PE (1 << 5) +# define SR_FE (1 << 6) +# define SR_BRK (1 << 7) +#define SCCNXP_CR_REG (0x02) +# define CR_RX_ENABLE (1 << 0) +# define CR_RX_DISABLE (1 << 1) +# define CR_TX_ENABLE (1 << 2) +# define CR_TX_DISABLE (1 << 3) +# define CR_CMD_MRPTR1 (0x01 << 4) +# define CR_CMD_RX_RESET (0x02 << 4) +# define CR_CMD_TX_RESET (0x03 << 4) +# define CR_CMD_STATUS_RESET (0x04 << 4) +# define CR_CMD_BREAK_RESET (0x05 << 4) +# define CR_CMD_START_BREAK (0x06 << 4) +# define CR_CMD_STOP_BREAK (0x07 << 4) +# define CR_CMD_MRPTR0 (0x0b << 4) +#define SCCNXP_RHR_REG (0x03) +#define SCCNXP_THR_REG SCCNXP_RHR_REG +#define SCCNXP_IPCR_REG (0x04) +#define SCCNXP_ACR_REG SCCNXP_IPCR_REG +# define ACR_BAUD0 (0 << 7) +# define ACR_BAUD1 (1 << 7) +# define ACR_TIMER_MODE (6 << 4) +#define SCCNXP_ISR_REG (0x05) +#define SCCNXP_IMR_REG SCCNXP_ISR_REG +# define IMR_TXRDY (1 << 0) +# define IMR_RXRDY (1 << 1) +# define ISR_TXRDY(x) (1 << ((x * 4) + 0)) +# define ISR_RXRDY(x) (1 << ((x * 4) + 1)) +#define SCCNXP_IPR_REG (0x0d) +#define SCCNXP_OPCR_REG SCCNXP_IPR_REG +#define SCCNXP_SOP_REG (0x0e) +#define SCCNXP_ROP_REG (0x0f) + +/* Route helpers */ +#define MCTRL_MASK(sig) (0xf << (sig)) +#define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0) +#define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0) + +/* Supported chip types */ +enum { + SCCNXP_TYPE_SC2681 = 2681, + SCCNXP_TYPE_SC2691 = 2691, + SCCNXP_TYPE_SC2692 = 2692, + SCCNXP_TYPE_SC2891 = 2891, + SCCNXP_TYPE_SC2892 = 2892, + SCCNXP_TYPE_SC28202 = 28202, + SCCNXP_TYPE_SC68681 = 68681, + SCCNXP_TYPE_SC68692 = 68692, +}; + +struct sccnxp_port { + struct uart_driver uart; + struct uart_port port[SCCNXP_MAX_UARTS]; + + const char *name; + int irq; + + u8 imr; + u8 addr_mask; + int freq_std; + + int flags; +#define SCCNXP_HAVE_IO 0x00000001 +#define SCCNXP_HAVE_MR0 0x00000002 + +#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE + struct console console; +#endif + + struct mutex sccnxp_mutex; + + struct sccnxp_pdata pdata; +}; + +static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift) +{ + return readb(base + (reg << shift)); +} + +static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v) +{ + writeb(v, base + (reg << shift)); +} + +static inline u8 sccnxp_read(struct uart_port *port, u8 reg) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + return sccnxp_raw_read(port->membase, reg & s->addr_mask, + port->regshift); +} + +static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v); +} + +static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg) +{ + return sccnxp_read(port, (port->line << 3) + reg); +} + +static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v) +{ + sccnxp_write(port, (port->line << 3) + reg, v); +} + +static int sccnxp_update_best_err(int a, int b, int *besterr) +{ + int err = abs(a - b); + + if ((*besterr < 0) || (*besterr > err)) { + *besterr = err; + return 0; + } + + return 1; +} + +struct baud_table { + u8 csr; + u8 acr; + u8 mr0; + int baud; +}; + +const struct baud_table baud_std[] = { + { 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, }, + { 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, }, + { 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, }, + { 2, ACR_BAUD0, MR0_BAUD_NORMAL, 134, }, + { 3, ACR_BAUD1, MR0_BAUD_NORMAL, 150, }, + { 3, ACR_BAUD0, MR0_BAUD_NORMAL, 200, }, + { 4, ACR_BAUD0, MR0_BAUD_NORMAL, 300, }, + { 0, ACR_BAUD1, MR0_BAUD_EXT1, 450, }, + { 1, ACR_BAUD0, MR0_BAUD_EXT2, 880, }, + { 3, ACR_BAUD1, MR0_BAUD_EXT1, 900, }, + { 5, ACR_BAUD0, MR0_BAUD_NORMAL, 600, }, + { 7, ACR_BAUD0, MR0_BAUD_NORMAL, 1050, }, + { 2, ACR_BAUD0, MR0_BAUD_EXT2, 1076, }, + { 6, ACR_BAUD0, MR0_BAUD_NORMAL, 1200, }, + { 10, ACR_BAUD1, MR0_BAUD_NORMAL, 1800, }, + { 7, ACR_BAUD1, MR0_BAUD_NORMAL, 2000, }, + { 8, ACR_BAUD0, MR0_BAUD_NORMAL, 2400, }, + { 5, ACR_BAUD1, MR0_BAUD_EXT1, 3600, }, + { 9, ACR_BAUD0, MR0_BAUD_NORMAL, 4800, }, + { 10, ACR_BAUD0, MR0_BAUD_NORMAL, 7200, }, + { 11, ACR_BAUD0, MR0_BAUD_NORMAL, 9600, }, + { 8, ACR_BAUD0, MR0_BAUD_EXT1, 14400, }, + { 12, ACR_BAUD1, MR0_BAUD_NORMAL, 19200, }, + { 9, ACR_BAUD0, MR0_BAUD_EXT1, 28800, }, + { 12, ACR_BAUD0, MR0_BAUD_NORMAL, 38400, }, + { 11, ACR_BAUD0, MR0_BAUD_EXT1, 57600, }, + { 12, ACR_BAUD1, MR0_BAUD_EXT1, 115200, }, + { 12, ACR_BAUD0, MR0_BAUD_EXT1, 230400, }, + { 0, 0, 0, 0 } +}; + +static void sccnxp_set_baud(struct uart_port *port, int baud) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + int div_std, tmp_baud, bestbaud = baud, besterr = -1; + u8 i, acr = 0, csr = 0, mr0 = 0; + + /* Find best baud from table */ + for (i = 0; baud_std[i].baud && besterr; i++) { + if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0)) + continue; + div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud); + tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std); + if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) { + acr = baud_std[i].acr; + csr = baud_std[i].csr; + mr0 = baud_std[i].mr0; + bestbaud = tmp_baud; + } + } + + if (s->flags & SCCNXP_HAVE_MR0) { + /* Enable FIFO, set half level for TX */ + mr0 |= MR0_FIFO | MR0_TXLVL; + /* Update MR0 */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR0); + sccnxp_port_write(port, SCCNXP_MR_REG, mr0); + } + + sccnxp_port_write(port, SCCNXP_ACR_REG, acr | ACR_TIMER_MODE); + sccnxp_port_write(port, SCCNXP_CSR_REG, (csr << 4) | csr); + + dev_dbg(port->dev, "Baudrate desired: %i, calculated: %i\n", + baud, bestbaud); +} + +static void sccnxp_enable_irq(struct uart_port *port, int mask) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + s->imr |= mask << (port->line * 4); + sccnxp_write(port, SCCNXP_IMR_REG, s->imr); +} + +static void sccnxp_disable_irq(struct uart_port *port, int mask) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + s->imr &= ~(mask << (port->line * 4)); + sccnxp_write(port, SCCNXP_IMR_REG, s->imr); +} + +static void sccnxp_set_bit(struct uart_port *port, int sig, int state) +{ + u8 bitmask; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(sig)) { + bitmask = 1 << MCTRL_OBIT(s->pdata.mctrl_cfg[port->line], sig); + if (state) + sccnxp_write(port, SCCNXP_SOP_REG, bitmask); + else + sccnxp_write(port, SCCNXP_ROP_REG, bitmask); + } +} + +static void sccnxp_handle_rx(struct uart_port *port) +{ + u8 sr; + unsigned int ch, flag; + struct tty_struct *tty = tty_port_tty_get(&port->state->port); + + if (!tty) + return; + + for (;;) { + sr = sccnxp_port_read(port, SCCNXP_SR_REG); + if (!(sr & SR_RXRDY)) + break; + sr &= SR_PE | SR_FE | SR_OVR | SR_BRK; + + ch = sccnxp_port_read(port, SCCNXP_RHR_REG); + + port->icount.rx++; + flag = TTY_NORMAL; + + if (unlikely(sr)) { + if (sr & SR_BRK) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sr & SR_PE) + port->icount.parity++; + else if (sr & SR_FE) + port->icount.frame++; + else if (sr & SR_OVR) + port->icount.overrun++; + + sr &= port->read_status_mask; + if (sr & SR_BRK) + flag = TTY_BREAK; + else if (sr & SR_PE) + flag = TTY_PARITY; + else if (sr & SR_FE) + flag = TTY_FRAME; + else if (sr & SR_OVR) + flag = TTY_OVERRUN; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (sr & port->ignore_status_mask) + continue; + + uart_insert_char(port, sr, SR_OVR, ch, flag); + } + + tty_flip_buffer_push(tty); + + tty_kref_put(tty); +} + +static void sccnxp_handle_tx(struct uart_port *port) +{ + u8 sr; + struct circ_buf *xmit = &port->state->xmit; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + if (unlikely(port->x_char)) { + sccnxp_port_write(port, SCCNXP_THR_REG, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + /* Disable TX if FIFO is empty */ + if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) { + sccnxp_disable_irq(port, IMR_TXRDY); + + /* Set direction to input */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(port, DIR_OP, 0); + } + return; + } + + while (!uart_circ_empty(xmit)) { + sr = sccnxp_port_read(port, SCCNXP_SR_REG); + if (!(sr & SR_TXRDY)) + break; + + sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static irqreturn_t sccnxp_ist(int irq, void *dev_id) +{ + int i; + u8 isr; + struct sccnxp_port *s = (struct sccnxp_port *)dev_id; + + mutex_lock(&s->sccnxp_mutex); + + for (;;) { + isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG); + isr &= s->imr; + if (!isr) + break; + + dev_dbg(s->port[0].dev, "IRQ status: 0x%02x\n", isr); + + for (i = 0; i < s->uart.nr; i++) { + if (isr & ISR_RXRDY(i)) + sccnxp_handle_rx(&s->port[i]); + if (isr & ISR_TXRDY(i)) + sccnxp_handle_tx(&s->port[i]); + } + } + + mutex_unlock(&s->sccnxp_mutex); + + return IRQ_HANDLED; +} + +static void sccnxp_start_tx(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + + /* Set direction to output */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(port, DIR_OP, 1); + + sccnxp_enable_irq(port, IMR_TXRDY); + + mutex_unlock(&s->sccnxp_mutex); +} + +static void sccnxp_stop_tx(struct uart_port *port) +{ + /* Do nothing */ +} + +static void sccnxp_stop_rx(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE); + mutex_unlock(&s->sccnxp_mutex); +} + +static unsigned int sccnxp_tx_empty(struct uart_port *port) +{ + u8 val; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + val = sccnxp_port_read(port, SCCNXP_SR_REG); + mutex_unlock(&s->sccnxp_mutex); + + return (val & SR_TXEMT) ? TIOCSER_TEMT : 0; +} + +static void sccnxp_enable_ms(struct uart_port *port) +{ + /* Do nothing */ +} + +static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + if (!(s->flags & SCCNXP_HAVE_IO)) + return; + + mutex_lock(&s->sccnxp_mutex); + + sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR); + sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS); + + mutex_unlock(&s->sccnxp_mutex); +} + +static unsigned int sccnxp_get_mctrl(struct uart_port *port) +{ + u8 bitmask, ipr; + struct sccnxp_port *s = dev_get_drvdata(port->dev); + unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; + + if (!(s->flags & SCCNXP_HAVE_IO)) + return mctrl; + + mutex_lock(&s->sccnxp_mutex); + + ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG); + + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DSR_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + DSR_IP); + mctrl &= ~TIOCM_DSR; + mctrl |= (ipr & bitmask) ? TIOCM_DSR : 0; + } + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(CTS_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + CTS_IP); + mctrl &= ~TIOCM_CTS; + mctrl |= (ipr & bitmask) ? TIOCM_CTS : 0; + } + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(DCD_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + DCD_IP); + mctrl &= ~TIOCM_CAR; + mctrl |= (ipr & bitmask) ? TIOCM_CAR : 0; + } + if (s->pdata.mctrl_cfg[port->line] & MCTRL_MASK(RNG_IP)) { + bitmask = 1 << MCTRL_IBIT(s->pdata.mctrl_cfg[port->line], + RNG_IP); + mctrl &= ~TIOCM_RNG; + mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0; + } + + mutex_unlock(&s->sccnxp_mutex); + + return mctrl; +} + +static void sccnxp_break_ctl(struct uart_port *port, int break_state) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + sccnxp_port_write(port, SCCNXP_CR_REG, break_state ? + CR_CMD_START_BREAK : CR_CMD_STOP_BREAK); + mutex_unlock(&s->sccnxp_mutex); +} + +static void sccnxp_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + u8 mr1, mr2; + int baud; + + mutex_lock(&s->sccnxp_mutex); + + /* Mask termios capabilities we don't support */ + termios->c_cflag &= ~CMSPAR; + termios->c_iflag &= ~(IXON | IXOFF | IXANY); + + /* Disable RX & TX, reset break condition, status and FIFOs */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET | + CR_RX_DISABLE | CR_TX_DISABLE); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); + + /* Word size */ + switch (termios->c_cflag & CSIZE) { + case CS5: + mr1 = MR1_BITS_5; + break; + case CS6: + mr1 = MR1_BITS_6; + break; + case CS7: + mr1 = MR1_BITS_7; + break; + default: + case CS8: + mr1 = MR1_BITS_8; + break; + } + + /* Parity */ + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & PARODD) + mr1 |= MR1_PAR_ODD; + } else + mr1 |= MR1_PAR_NO; + + /* Stop bits */ + mr2 = (termios->c_cflag & CSTOPB) ? MR2_STOP2 : MR2_STOP1; + + /* Update desired format */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_MRPTR1); + sccnxp_port_write(port, SCCNXP_MR_REG, mr1); + sccnxp_port_write(port, SCCNXP_MR_REG, mr2); + + /* Set read status mask */ + port->read_status_mask = SR_OVR; + if (termios->c_iflag & INPCK) + port->read_status_mask |= SR_PE | SR_FE; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SR_BRK; + + /* Set status ignore mask */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNBRK) + port->ignore_status_mask |= SR_BRK; + if (!(termios->c_cflag & CREAD)) + port->ignore_status_mask |= SR_PE | SR_OVR | SR_FE | SR_BRK; + + /* Setup baudrate */ + baud = uart_get_baud_rate(port, termios, old, 50, + (s->flags & SCCNXP_HAVE_MR0) ? + 230400 : 38400); + sccnxp_set_baud(port, baud); + + /* Update timeout according to new baud rate */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* Enable RX & TX */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); + + mutex_unlock(&s->sccnxp_mutex); +} + +static int sccnxp_startup(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + + if (s->flags & SCCNXP_HAVE_IO) { + /* Outputs are controlled manually */ + sccnxp_write(port, SCCNXP_OPCR_REG, 0); + } + + /* Reset break condition, status and FIFOs */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_RX_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_TX_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_STATUS_RESET); + sccnxp_port_write(port, SCCNXP_CR_REG, CR_CMD_BREAK_RESET); + + /* Enable RX & TX */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE); + + /* Enable RX interrupt */ + sccnxp_enable_irq(port, IMR_RXRDY); + + mutex_unlock(&s->sccnxp_mutex); + + return 0; +} + +static void sccnxp_shutdown(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + mutex_lock(&s->sccnxp_mutex); + + /* Disable interrupts */ + sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + + /* Disable TX & RX */ + sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE); + + /* Leave direction to input */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(port, DIR_OP, 0); + + mutex_unlock(&s->sccnxp_mutex); +} + +static const char *sccnxp_type(struct uart_port *port) +{ + struct sccnxp_port *s = dev_get_drvdata(port->dev); + + return (port->type == PORT_SC26XX) ? s->name : NULL; +} + +static void sccnxp_release_port(struct uart_port *port) +{ + /* Do nothing */ +} + +static int sccnxp_request_port(struct uart_port *port) +{ + /* Do nothing */ + return 0; +} + +static void sccnxp_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_SC26XX; +} + +static int sccnxp_verify_port(struct uart_port *port, struct serial_struct *s) +{ + if ((s->type == PORT_UNKNOWN) || (s->type == PORT_SC26XX)) + return 0; + if (s->irq == port->irq) + return 0; + + return -EINVAL; +} + +static const struct uart_ops sccnxp_ops = { + .tx_empty = sccnxp_tx_empty, + .set_mctrl = sccnxp_set_mctrl, + .get_mctrl = sccnxp_get_mctrl, + .stop_tx = sccnxp_stop_tx, + .start_tx = sccnxp_start_tx, + .stop_rx = sccnxp_stop_rx, + .enable_ms = sccnxp_enable_ms, + .break_ctl = sccnxp_break_ctl, + .startup = sccnxp_startup, + .shutdown = sccnxp_shutdown, + .set_termios = sccnxp_set_termios, + .type = sccnxp_type, + .release_port = sccnxp_release_port, + .request_port = sccnxp_request_port, + .config_port = sccnxp_config_port, + .verify_port = sccnxp_verify_port, +}; + +#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE +static void sccnxp_console_putchar(struct uart_port *port, int c) +{ + int tryes = 100000; + + while (tryes--) { + if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXRDY) { + sccnxp_port_write(port, SCCNXP_THR_REG, c); + break; + } + barrier(); + } +} + +static void sccnxp_console_write(struct console *co, const char *c, unsigned n) +{ + struct sccnxp_port *s = (struct sccnxp_port *)co->data; + struct uart_port *port = &s->port[co->index]; + + mutex_lock(&s->sccnxp_mutex); + uart_console_write(port, c, n, sccnxp_console_putchar); + mutex_unlock(&s->sccnxp_mutex); +} + +static int sccnxp_console_setup(struct console *co, char *options) +{ + struct sccnxp_port *s = (struct sccnxp_port *)co->data; + struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0]; + int baud = 9600, bits = 8, parity = 'n', flow = 'n'; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} +#endif + +static int __devinit sccnxp_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int chiptype = pdev->id_entry->driver_data; + struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); + int i, ret, fifosize, freq_min, freq_max; + struct sccnxp_port *s; + void __iomem *membase; + + if (!res) { + dev_err(&pdev->dev, "Missing memory resource data\n"); + return -EADDRNOTAVAIL; + } + + dev_set_name(&pdev->dev, SCCNXP_NAME); + + s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL); + if (!s) { + dev_err(&pdev->dev, "Error allocating port structure\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, s); + + mutex_init(&s->sccnxp_mutex); + + /* Individual chip settings */ + switch (chiptype) { + case SCCNXP_TYPE_SC2681: + s->name = "SC2681"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC2691: + s->name = "SC2691"; + s->uart.nr = 1; + s->freq_std = 3686400; + s->addr_mask = 0x07; + s->flags = 0; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC2692: + s->name = "SC2692"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC2891: + s->name = "SC2891"; + s->uart.nr = 1; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; + fifosize = 16; + freq_min = 100000; + freq_max = 8000000; + break; + case SCCNXP_TYPE_SC2892: + s->name = "SC2892"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; + fifosize = 16; + freq_min = 100000; + freq_max = 8000000; + break; + case SCCNXP_TYPE_SC28202: + s->name = "SC28202"; + s->uart.nr = 2; + s->freq_std = 14745600; + s->addr_mask = 0x7f; + s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; + fifosize = 256; + freq_min = 1000000; + freq_max = 50000000; + break; + case SCCNXP_TYPE_SC68681: + s->name = "SC68681"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + case SCCNXP_TYPE_SC68692: + s->name = "SC68692"; + s->uart.nr = 2; + s->freq_std = 3686400; + s->addr_mask = 0x0f; + s->flags = SCCNXP_HAVE_IO; + fifosize = 3; + freq_min = 1000000; + freq_max = 4000000; + break; + default: + dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype); + ret = -ENOTSUPP; + goto err_out; + } + + if (!pdata) { + dev_warn(&pdev->dev, + "No platform data supplied, using defaults\n"); + s->pdata.frequency = s->freq_std; + } else + memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); + + s->irq = platform_get_irq(pdev, 0); + if (s->irq <= 0) { + dev_err(&pdev->dev, "Missing irq resource data\n"); + ret = -ENXIO; + goto err_out; + } + + /* Check input frequency */ + if ((s->pdata.frequency < freq_min) || + (s->pdata.frequency > freq_max)) { + dev_err(&pdev->dev, "Frequency out of bounds\n"); + ret = -EINVAL; + goto err_out; + } + + membase = devm_request_and_ioremap(&pdev->dev, res); + if (!membase) { + dev_err(&pdev->dev, "Failed to ioremap\n"); + ret = -EIO; + goto err_out; + } + + s->uart.owner = THIS_MODULE; + s->uart.dev_name = "ttySC"; + s->uart.major = SCCNXP_MAJOR; + s->uart.minor = SCCNXP_MINOR; +#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE + s->uart.cons = &s->console; + s->uart.cons->device = uart_console_device; + s->uart.cons->write = sccnxp_console_write; + s->uart.cons->setup = sccnxp_console_setup; + s->uart.cons->flags = CON_PRINTBUFFER; + s->uart.cons->index = -1; + s->uart.cons->data = s; + strcpy(s->uart.cons->name, "ttySC"); +#endif + ret = uart_register_driver(&s->uart); + if (ret) { + dev_err(&pdev->dev, "Registering UART driver failed\n"); + goto err_out; + } + + for (i = 0; i < s->uart.nr; i++) { + s->port[i].line = i; + s->port[i].dev = &pdev->dev; + s->port[i].irq = s->irq; + s->port[i].type = PORT_SC26XX; + s->port[i].fifosize = fifosize; + s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; + s->port[i].iotype = UPIO_MEM; + s->port[i].mapbase = res->start; + s->port[i].membase = membase; + s->port[i].regshift = s->pdata.reg_shift; + s->port[i].uartclk = s->pdata.frequency; + s->port[i].ops = &sccnxp_ops; + uart_add_one_port(&s->uart, &s->port[i]); + /* Set direction to input */ + if (s->flags & SCCNXP_HAVE_IO) + sccnxp_set_bit(&s->port[i], DIR_OP, 0); + } + + /* Disable interrupts */ + s->imr = 0; + sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0); + + /* Board specific configure */ + if (s->pdata.init) + s->pdata.init(); + + ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, sccnxp_ist, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&pdev->dev), s); + if (!ret) + return 0; + + dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq); + +err_out: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __devexit sccnxp_remove(struct platform_device *pdev) +{ + int i; + struct sccnxp_port *s = platform_get_drvdata(pdev); + + devm_free_irq(&pdev->dev, s->irq, s); + + for (i = 0; i < s->uart.nr; i++) + uart_remove_one_port(&s->uart, &s->port[i]); + + uart_unregister_driver(&s->uart); + platform_set_drvdata(pdev, NULL); + + if (s->pdata.exit) + s->pdata.exit(); + + return 0; +} + +static const struct platform_device_id sccnxp_id_table[] = { + { "sc2681", SCCNXP_TYPE_SC2681 }, + { "sc2691", SCCNXP_TYPE_SC2691 }, + { "sc2692", SCCNXP_TYPE_SC2692 }, + { "sc2891", SCCNXP_TYPE_SC2891 }, + { "sc2892", SCCNXP_TYPE_SC2892 }, + { "sc28202", SCCNXP_TYPE_SC28202 }, + { "sc68681", SCCNXP_TYPE_SC68681 }, + { "sc68692", SCCNXP_TYPE_SC68692 }, +}; +MODULE_DEVICE_TABLE(platform, sccnxp_id_table); + +static struct platform_driver sccnxp_uart_driver = { + .driver = { + .name = SCCNXP_NAME, + .owner = THIS_MODULE, + }, + .probe = sccnxp_probe, + .remove = __devexit_p(sccnxp_remove), + .id_table = sccnxp_id_table, +}; +module_platform_driver(sccnxp_uart_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("SCCNXP serial driver"); diff --git a/include/linux/platform_data/sccnxp.h b/include/linux/platform_data/sccnxp.h new file mode 100644 index 0000000..7311ccd --- /dev/null +++ b/include/linux/platform_data/sccnxp.h @@ -0,0 +1,93 @@ +/* + * NXP (Philips) SCC+++(SCN+++) serial driver + * + * Copyright (C) 2012 Alexander Shiyan + * + * Based on sc26xx.c, by Thomas Bogendörfer (tsbogend@alpha.franken.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __SCCNXP_H +#define __SCCNXP_H + +#define SCCNXP_MAX_UARTS 2 + +/* Output lines */ +#define LINE_OP0 1 +#define LINE_OP1 2 +#define LINE_OP2 3 +#define LINE_OP3 4 +#define LINE_OP4 5 +#define LINE_OP5 6 +#define LINE_OP6 7 +#define LINE_OP7 8 + +/* Input lines */ +#define LINE_IP0 9 +#define LINE_IP1 10 +#define LINE_IP2 11 +#define LINE_IP3 12 +#define LINE_IP4 13 +#define LINE_IP5 14 +#define LINE_IP6 15 + +/* Signals */ +#define DTR_OP 0 /* DTR */ +#define RTS_OP 4 /* RTS */ +#define DSR_IP 8 /* DSR */ +#define CTS_IP 12 /* CTS */ +#define DCD_IP 16 /* DCD */ +#define RNG_IP 20 /* RNG */ + +#define DIR_OP 24 /* Special signal for control RS-485. + * Goes high when transmit, + * then goes low. + */ + +/* Routing control signal 'sig' to line 'line' */ +#define MCTRL_SIG(sig, line) ((line) << (sig)) + +/* + * Example board initialization data: + * + * static struct resource sc2892_resources[] = { + * DEFINE_RES_MEM(UART_PHYS_START, 0x10), + * DEFINE_RES_IRQ(IRQ_EXT2), + * }; + * + * static struct sccnxp_pdata sc2892_info = { + * .frequency = 3686400, + * .mctrl_cfg[0] = MCTRL_SIG(DIR_OP, LINE_OP0), + * .mctrl_cfg[1] = MCTRL_SIG(DIR_OP, LINE_OP1), + * }; + * + * static struct platform_device sc2892 = { + * .name = "sc2892", + * .id = -1, + * .resource = sc2892_resources, + * .num_resources = ARRAY_SIZE(sc2892_resources), + * .dev = { + * .platform_data = &sc2892_info, + * }, + * }; + */ + +/* SCCNXP platform data structure */ +struct sccnxp_pdata { + /* Frequency (extrenal clock or crystal) */ + int frequency; + /* Shift for A0 line */ + const u8 reg_shift; + /* Modem control lines configuration */ + const u32 mctrl_cfg[SCCNXP_MAX_UARTS]; + /* Called during startup */ + void (*init)(void); + /* Called before finish */ + void (*exit)(void); +}; + +#endif -- cgit v0.10.2 From be282059acebcecd789fad1b3d17d826db3d5608 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 25 Aug 2012 19:24:20 +0400 Subject: serial: Add note about migration to driver SCCNXP This patch adds note about migration to driver SCCNXP in the code of driver SC26XX and in MIPS SNI board initialization with example. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c index c48194c..b2d4f49 100644 --- a/arch/mips/sni/a20r.c +++ b/arch/mips/sni/a20r.c @@ -133,6 +133,38 @@ static struct platform_device sc26xx_pdev = { } }; +#warning "Please try migrate to use new driver SCCNXP and report the status" \ + "in the linux-serial mailing list." + +/* The code bellow is a replacement of SC26XX to SCCNXP */ +#if 0 +#include + +static struct sccnxp_pdata sccnxp_data = { + .reg_shift = 2, + .frequency = 3686400, + .mctrl_cfg[0] = MCTRL_SIG(DTR_OP, LINE_OP7) | + MCTRL_SIG(RTS_OP, LINE_OP3) | + MCTRL_SIG(DSR_IP, LINE_IP5) | + MCTRL_SIG(DCD_IP, LINE_IP6), + .mctrl_cfg[1] = MCTRL_SIG(DTR_OP, LINE_OP2) | + MCTRL_SIG(RTS_OP, LINE_OP1) | + MCTRL_SIG(DSR_IP, LINE_IP0) | + MCTRL_SIG(CTS_IP, LINE_IP1) | + MCTRL_SIG(DCD_IP, LINE_IP2) | + MCTRL_SIG(RNG_IP, LINE_IP3), +}; + +static struct platform_device sc2681_pdev = { + .name = "sc2681", + .resource = sc2xxx_rsrc, + .num_resources = ARRAY_SIZE(sc2xxx_rsrc), + .dev = { + .platform_data = &sccnxp_data, + }, +}; +#endif + static u32 a20r_ack_hwint(void) { u32 status = read_c0_status(); diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c index 3992e48..9d66424 100644 --- a/drivers/tty/serial/sc26xx.c +++ b/drivers/tty/serial/sc26xx.c @@ -22,6 +22,9 @@ #include #include +#warning "Please try migrate to use new driver SCCNXP and report the status" \ + "in the linux-serial mailing list." + #if defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif -- cgit v0.10.2 From c990f3510357586be63bbe9faf7972212a0dc78f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 23 Aug 2012 13:32:41 +0300 Subject: serial: omap: define and use to_uart_omap_port() current code only works because struct uart_port is the first member on the uart_omap_port structure. If, for whatever reason, someone puts another member as the first of the structure, that cast won't work anymore. In order to be safe, let's use a container_of() which, for now, gets optimized into a cast anyway. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Acked-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 52d3de4..5cc0626 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -144,4 +144,6 @@ struct uart_omap_port { struct work_struct qos_work; }; +#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) + #endif /* __OMAP_SERIAL_H__ */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index aa603f2..8d7a18a 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -142,7 +142,7 @@ static void serial_omap_stop_rxdma(struct uart_omap_port *up) static void serial_omap_enable_ms(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line); @@ -154,7 +154,7 @@ static void serial_omap_enable_ms(struct uart_port *port) static void serial_omap_stop_tx(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; if (up->use_dma && @@ -187,7 +187,7 @@ static void serial_omap_stop_tx(struct uart_port *port) static void serial_omap_stop_rx(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); pm_runtime_get_sync(&up->pdev->dev); if (up->use_dma) @@ -308,7 +308,7 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) static void serial_omap_start_tx(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; struct circ_buf *xmit; unsigned int start; @@ -450,7 +450,7 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) static unsigned int serial_omap_tx_empty(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; unsigned int ret = 0; @@ -465,7 +465,7 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port) static unsigned int serial_omap_get_mctrl(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned int status; unsigned int ret = 0; @@ -488,7 +488,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned char mcr = 0; dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line); @@ -522,7 +522,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) static void serial_omap_break_ctl(struct uart_port *port, int break_state) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); @@ -539,7 +539,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) static int serial_omap_startup(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; int retval; @@ -617,7 +617,7 @@ static int serial_omap_startup(struct uart_port *port) static void serial_omap_shutdown(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags = 0; dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line); @@ -735,7 +735,7 @@ static void serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned char cval = 0; unsigned char efr = 0; unsigned long flags = 0; @@ -946,7 +946,7 @@ static void serial_omap_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned char efr; dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line); @@ -985,7 +985,7 @@ static int serial_omap_request_port(struct uart_port *port) static void serial_omap_config_port(struct uart_port *port, int flags) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); dev_dbg(up->port.dev, "serial_omap_config_port+%d\n", up->port.line); @@ -1003,7 +1003,7 @@ serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser) static const char * serial_omap_type(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->port.line); return up->name; @@ -1046,7 +1046,7 @@ static inline void wait_for_xmitr(struct uart_omap_port *up) static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); pm_runtime_get_sync(&up->pdev->dev); wait_for_xmitr(up); @@ -1056,7 +1056,7 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) static int serial_omap_poll_get_char(struct uart_port *port) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); unsigned int status; pm_runtime_get_sync(&up->pdev->dev); @@ -1079,7 +1079,7 @@ static struct uart_driver serial_omap_reg; static void serial_omap_console_putchar(struct uart_port *port, int ch) { - struct uart_omap_port *up = (struct uart_omap_port *)port; + struct uart_omap_port *up = to_uart_omap_port(port); wait_for_xmitr(up); serial_out(up, UART_TX, ch); @@ -1355,7 +1355,7 @@ static void serial_omap_continue_tx(struct uart_omap_port *up) static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) { - struct uart_omap_port *up = (struct uart_omap_port *)data; + struct uart_omap_port *up = data; struct circ_buf *xmit = &up->port.state->xmit; xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \ -- cgit v0.10.2 From e5b57c037a656c694c7f3674f96352297a6ee7d8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 23 Aug 2012 13:32:42 +0300 Subject: serial: omap: define helpers for pdata function pointers this patch is in preparation to a few other changes which will align on the prototype for function pointers passed through pdata. It also helps cleaning up the driver a little by agregating checks for pdata in a single location. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 8d7a18a..3a60b86 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -102,6 +102,40 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up) serial_out(up, UART_FCR, 0); } +static int serial_omap_get_context_loss_count(struct uart_omap_port *up) +{ + struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + + if (!pdata->get_context_loss_count) + return 0; + + return pdata->get_context_loss_count(&up->pdev->dev); +} + +static void serial_omap_set_forceidle(struct uart_omap_port *up) +{ + struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + + if (pdata->set_forceidle) + pdata->set_forceidle(up->pdev); +} + +static void serial_omap_set_noidle(struct uart_omap_port *up) +{ + struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + + if (pdata->set_noidle) + pdata->set_noidle(up->pdev); +} + +static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) +{ + struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + + if (pdata->enable_wakeup) + pdata->enable_wakeup(up->pdev, enable); +} + /* * serial_omap_get_divisor - calculate divisor value * @port: uart port info @@ -178,8 +212,8 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } - if (!up->use_dma && pdata && pdata->set_forceidle) - pdata->set_forceidle(up->pdev); + if (!up->use_dma && pdata) + serial_omap_set_forceidle(up); pm_runtime_mark_last_busy(&up->pdev->dev); pm_runtime_put_autosuspend(&up->pdev->dev); @@ -309,7 +343,6 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) static void serial_omap_start_tx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; struct circ_buf *xmit; unsigned int start; int ret = 0; @@ -317,8 +350,7 @@ static void serial_omap_start_tx(struct uart_port *port) if (!up->use_dma) { pm_runtime_get_sync(&up->pdev->dev); serial_omap_enable_ier_thri(up); - if (pdata && pdata->set_noidle) - pdata->set_noidle(up->pdev); + serial_omap_set_noidle(up); pm_runtime_mark_last_busy(&up->pdev->dev); pm_runtime_put_autosuspend(&up->pdev->dev); return; @@ -1681,28 +1713,26 @@ static int serial_omap_runtime_suspend(struct device *dev) if (!up) return -EINVAL; - if (!pdata || !pdata->enable_wakeup) + if (!pdata) return 0; - if (pdata->get_context_loss_count) - up->context_loss_cnt = pdata->get_context_loss_count(dev); + up->context_loss_cnt = serial_omap_get_context_loss_count(up); if (device_may_wakeup(dev)) { if (!up->wakeups_enabled) { - pdata->enable_wakeup(up->pdev, true); + serial_omap_enable_wakeup(up, true); up->wakeups_enabled = true; } } else { if (up->wakeups_enabled) { - pdata->enable_wakeup(up->pdev, false); + serial_omap_enable_wakeup(up, false); up->wakeups_enabled = false; } } /* Errata i291 */ - if (up->use_dma && pdata->set_forceidle && - (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) - pdata->set_forceidle(up->pdev); + if (up->use_dma && (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) + serial_omap_set_forceidle(up); up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&up->qos_work); @@ -1716,17 +1746,15 @@ static int serial_omap_runtime_resume(struct device *dev) struct omap_uart_port_info *pdata = dev->platform_data; if (up && pdata) { - if (pdata->get_context_loss_count) { - u32 loss_cnt = pdata->get_context_loss_count(dev); + u32 loss_cnt = serial_omap_get_context_loss_count(up); if (up->context_loss_cnt != loss_cnt) serial_omap_restore_context(up); - } /* Errata i291 */ - if (up->use_dma && pdata->set_noidle && - (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) - pdata->set_noidle(up->pdev); + if ((up->errata & UART_ERRATA_i291_DMA_FORCEIDLE) && + up->use_dma) + serial_omap_set_noidle(up); up->latency = up->calc_latency; schedule_work(&up->qos_work); -- cgit v0.10.2 From f21ec3d2d46e5f2ffc06f31fe2704fdcea7a58f3 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 22 Aug 2012 22:13:36 -0400 Subject: serial: add a new helper function In most of the time, the driver needs to check if the cts flow control is enabled. But now, the driver checks the ASYNC_CTS_FLOW flag manually, which is not a grace way. So add a new wraper function to make the code tidy and clean. Signed-off-by: Huang Shijie Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 5db08c7..3f57d5de 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1050,7 +1050,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty) wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); - if (info->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&info->port)) { if (tty->hw_stopped) { if (info->serial_signals & SerialSignal_CTS) { if (debug_level >= DEBUG_LEVEL_ISR) diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 2b7535d..42d0a25 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -420,7 +420,7 @@ static void check_modem_status(struct serial_state *info) tty_hangup(port->tty); } } - if (port->flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(port)) { if (port->tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c index e3954da..0a6a0bc 100644 --- a/drivers/tty/cyclades.c +++ b/drivers/tty/cyclades.c @@ -727,7 +727,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, else tty_hangup(tty); } - if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) { + if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) { if (tty->hw_stopped) { if (mdm_status & CyCTS) { /* cy_start isn't used diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index 99cf22e..d7492e1 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -600,7 +600,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) port->status &= ~ISI_DCD; } - if (port->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&port->port)) { if (tty->hw_stopped) { if (header & ISI_CTS) { port->port.tty->hw_stopped = 0; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index bb2da4c..cfda47d 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -830,7 +830,7 @@ static void mxser_check_modem_status(struct tty_struct *tty, wake_up_interruptible(&port->port.open_wait); } - if (port->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&port->port)) { if (tty->hw_stopped) { if (status & UART_MSR_CTS) { tty->hw_stopped = 0; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 3a667ee..dafeef2 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -262,7 +262,7 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) ctrl &= ~AUART_CTRL2_RTSEN; if (mctrl & TIOCM_RTS) { - if (u->state->port.flags & ASYNC_CTS_FLOW) + if (tty_port_cts_enabled(&u->state->port)) ctrl |= AUART_CTRL2_RTSEN; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index bb5f236..137b25c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -176,7 +176,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } - if (port->flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(port)) { spin_lock_irq(&uport->lock); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -2509,7 +2509,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status) uport->icount.cts++; - if (port->flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(port)) { if (tty->hw_stopped) { if (status) { tty->hw_stopped = 0; diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 666aa14..70e3a52 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -1359,7 +1359,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info ) } } - if ( (info->port.flags & ASYNC_CTS_FLOW) && + if (tty_port_cts_enabled(&info->port) && (status & MISCSTATUS_CTS_LATCHED) ) { if (info->port.tty->hw_stopped) { if (status & MISCSTATUS_CTS) { diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 45f6136..b38e954 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -2053,7 +2053,7 @@ static void cts_change(struct slgt_info *info, unsigned short status) wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; - if (info->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&info->port)) { if (info->port.tty) { if (info->port.tty->hw_stopped) { if (info->signals & SerialSignal_CTS) { diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 53429c8..f17d9f3 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -2500,7 +2500,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status ) } } - if ( (info->port.flags & ASYNC_CTS_FLOW) && + if (tty_port_cts_enabled(&info->port) && (status & MISCSTATUS_CTS_LATCHED) ) { if ( info->port.tty ) { if (info->port.tty->hw_stopped) { diff --git a/include/linux/tty.h b/include/linux/tty.h index dbebd1e..9892121 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -514,6 +514,12 @@ static inline struct tty_port *tty_port_get(struct tty_port *port) return port; } +/* If the cts flow control is enabled, return true. */ +static inline bool tty_port_cts_enabled(struct tty_port *port) +{ + return port->flags & ASYNC_CTS_FLOW; +} + extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); extern int tty_port_carrier_raised(struct tty_port *port); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index 9668990..95a3a7a 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -1070,7 +1070,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) goto put; } } - if (tty && self->port.flags & ASYNC_CTS_FLOW) { + if (tty && tty_port_cts_enabled(&self->port)) { if (tty->hw_stopped) { if (status & IRCOMM_CTS) { IRDA_DEBUG(2, @@ -1313,7 +1313,7 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) seq_puts(m, "Flags:"); sep = ' '; - if (self->port.flags & ASYNC_CTS_FLOW) { + if (tty_port_cts_enabled(&self->port)) { seq_printf(m, "%cASYNC_CTS_FLOW", sep); sep = '|'; } diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index 3ab70e7..edab393 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -578,7 +578,7 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self) * will have to wait for the peer device (DCE) to raise the CTS * line. */ - if ((self->port.flags & ASYNC_CTS_FLOW) && + if (tty_port_cts_enabled(&self->port) && ((self->settings.dce & IRCOMM_CTS) == 0)) { IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ ); goto put; -- cgit v0.10.2 From 9986ffd9032a103df54fa4ed85f8f83f6b215194 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 3 Sep 2012 18:09:53 +0800 Subject: parport: fix possible memory leak in parport_gsc_probe_port() ops has been allocated in this function and should be freed before leaving from the error handling cases. spatch with a semantic match is used to found this problem. (http://coccinelle.lip6.fr/) Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 5d6de38..352f961 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -271,6 +271,7 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base, if (!parport_SPP_supported (p)) { /* No port. */ kfree (priv); + kfree(ops); return NULL; } parport_PS2_supported (p); -- cgit v0.10.2 From 27788c5fe6af98c34950326b62778da15e30eb55 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Sep 2012 16:21:06 +0100 Subject: 8250_pci: Add additional WCH CHC353 devices These were reported in bugzilla long ago with a hack patch. Now we have a proper patch for one we can do the rest. Resolves-bug: https://bugzilla.kernel.org/show_bug.cgi?id=25102 Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 803d313..fdab80a 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1204,6 +1204,10 @@ pci_wch_ch353_setup(struct serial_private *priv, #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d +#define PCI_VENDOR_ID_WCH 0x4348 +#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453 +#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 +#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 #define PCI_VENDOR_ID_AGESTAR 0x5372 #define PCI_DEVICE_ID_AGESTAR_9375 0x6872 #define PCI_VENDOR_ID_ASIX 0x9710 @@ -1749,10 +1753,26 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { }, /* WCH CH353 2S1P card (16550 clone) */ { - .vendor = 0x4348, - .device = 0x7053, - .subvendor = 0x4348, - .subdevice = 0x3253, + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH353_2S1P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, + /* WCH CH353 4S card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH353_4S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_wch_ch353_setup, + }, + /* WCH CH353 2S1PF card (16550 clone) */ + { + .vendor = PCI_VENDOR_ID_WCH, + .device = PCI_DEVICE_ID_WCH_CH353_2S1PF, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, /* @@ -4218,6 +4238,19 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, + + /* + * WCH CH353 series devices: The 2S1P is handled by parport_serial + * so not listed here. + */ + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_4_115200 }, + + { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_b0_bt_2_115200 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL -- cgit v0.10.2 From ed6fe9d614fc1bca95eb8c0ccd0e92db00ef9d5d Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Sat, 1 Sep 2012 12:34:07 -0400 Subject: Fix order of arguments to compat_put_time[spec|val] Commit 644595f89620 ("compat: Handle COMPAT_USE_64BIT_TIME in net/socket.c") introduced a bug where the helper functions to take either a 64-bit or compat time[spec|val] got the arguments in the wrong order, passing the kernel stack pointer off as a user pointer (and vice versa). Because of the user address range check, that in turn then causes an EFAULT due to the user pointer range checking failing for the kernel address. Incorrectly resuling in a failed system call for 32-bit processes with a 64-bit kernel. On odder architectures like HP-PA (with separate user/kernel address spaces), it can be used read kernel memory. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds diff --git a/net/socket.c b/net/socket.c index a5471f8..edc3c4a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2604,7 +2604,7 @@ static int do_siocgstamp(struct net *net, struct socket *sock, err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); set_fs(old_fs); if (!err) - err = compat_put_timeval(up, &ktv); + err = compat_put_timeval(&ktv, up); return err; } @@ -2620,7 +2620,7 @@ static int do_siocgstampns(struct net *net, struct socket *sock, err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); set_fs(old_fs); if (!err) - err = compat_put_timespec(up, &kts); + err = compat_put_timespec(&kts, up); return err; } -- cgit v0.10.2 From 8a55ade76551e3927b4e41ee9e7751875d18bc25 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 4 Sep 2012 15:10:08 +0100 Subject: dj: memory scribble in logi_dj Allocate a structure not a pointer to it ! Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 0f9c146..4d524b5 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -439,7 +439,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev) struct dj_report *dj_report; int retval; - dj_report = kzalloc(sizeof(dj_report), GFP_KERNEL); + dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); if (!dj_report) return -ENOMEM; dj_report->report_id = REPORT_ID_DJ_SHORT; @@ -456,7 +456,7 @@ static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, struct dj_report *dj_report; int retval; - dj_report = kzalloc(sizeof(dj_report), GFP_KERNEL); + dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL); if (!dj_report) return -ENOMEM; dj_report->report_id = REPORT_ID_DJ_SHORT; -- cgit v0.10.2 From bc6c83641e1df61cff67748987f95ca62953565e Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 5 Sep 2012 18:38:50 +0200 Subject: uml: fix compile error in deliver_alarm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following compile error on UML. arch/um/os-Linux/time.c: In function 'deliver_alarm': arch/um/os-Linux/time.c:117:3: error: too few arguments to function 'alarm_handler' arch/um/os-Linux/internal.h:1:6: note: declared here The error was introduced by commit d3c1cfcd ("um: pass siginfo to guest process") in 3.6-rc1. Signed-off-by: Miklos Szeredi CC: Martin Pärtel Signed-off-by: Linus Torvalds diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c index f602385..0748fe0 100644 --- a/arch/um/os-Linux/time.c +++ b/arch/um/os-Linux/time.c @@ -114,7 +114,7 @@ static void deliver_alarm(void) skew += this_tick - last_tick; while (skew >= one_tick) { - alarm_handler(SIGVTALRM, NULL); + alarm_handler(SIGVTALRM, NULL, NULL); skew -= one_tick; } -- cgit v0.10.2 From 3956a1a0d1e072c321fcf1b1136e35a22be12af5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 23 Aug 2012 16:54:09 +0300 Subject: ARM: OMAP: omap_device: Fix up resource names when booted with devicetree When booted with some resource will have their name set to NULL. This can cause later kernel crash since this is not expected by the platform code. When we boot without DT the devices are created with platform_device_add() which itself fixes up the missing resource names: if (r->name == NULL) r->name = dev_name(&pdev->dev); The of core also fixes up the resource names when taking the information from DT data - in __of_address_to_resource(): r->name = name ? name : dev->full_name; When we boot OMAP with devicetree: of will create the devices based on the DT data so the resource names are guarantied to be not NULL. Since we have the 'ti,hwmod' tag, we remove the of created resources from the device and re-create them based on hwmod data. If the hwmod data does not specify a name for a resource it will be NULL. This can cause kernel crash if the driver uses platform_get_resource_byname() to get any resource. Signed-off-by: Peter Ujfalusi [b-cousson@ti.com: Change omap_hwmod to omap_device in subject] Signed-off-by: Benoit Cousson diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index c490240..ff57b5a 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -370,6 +370,14 @@ static int omap_device_build_from_dt(struct platform_device *pdev) goto odbfd_exit1; } + /* Fix up missing resource names */ + for (i = 0; i < pdev->num_resources; i++) { + struct resource *r = &pdev->resource[i]; + + if (r->name == NULL) + r->name = dev_name(&pdev->dev); + } + if (of_get_property(node, "ti,no_idle_on_suspend", NULL)) omap_device_disable_idle_on_suspend(pdev); -- cgit v0.10.2 From 80ba77dfbce85f2d1be54847de3c866de1b18a9a Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 5 Sep 2012 16:35:20 -0400 Subject: xen/pciback: Fix proper FLR steps. When we do FLR and save PCI config we did it in the wrong order. The end result was that if a PCI device was unbind from its driver, then binded to xen-pciback, and then back to its driver we would get: > lspci -s 04:00.0 04:00.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection 13:42:12 # 4 :~/ > echo "0000:04:00.0" > /sys/bus/pci/drivers/pciback/unbind > modprobe e1000e e1000e: Intel(R) PRO/1000 Network Driver - 2.0.0-k e1000e: Copyright(c) 1999 - 2012 Intel Corporation. e1000e 0000:04:00.0: Disabling ASPM L0s L1 e1000e 0000:04:00.0: enabling device (0000 -> 0002) xen: registering gsi 48 triggering 0 polarity 1 Already setup the GSI :48 e1000e 0000:04:00.0: Interrupt Throttling Rate (ints/sec) set to dynamic conservative mode e1000e: probe of 0000:04:00.0 failed with error -2 This fixes it by first saving the PCI configuration space, then doing the FLR. Reported-by: Ren, Yongjie Reported-and-Tested-by: Tobias Geiger Signed-off-by: Konrad Rzeszutek Wilk CC: stable@vger.kernel.org diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 097e536..0334272 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -353,16 +353,16 @@ static int __devinit pcistub_init_device(struct pci_dev *dev) if (err) goto config_release; - dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); - __pci_reset_function_locked(dev); - /* We need the device active to save the state. */ dev_dbg(&dev->dev, "save state of device\n"); pci_save_state(dev); dev_data->pci_saved_state = pci_store_saved_state(dev); if (!dev_data->pci_saved_state) dev_err(&dev->dev, "Could not store PCI conf saved state!\n"); - + else { + dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); + __pci_reset_function_locked(dev); + } /* Now disable the device (this also ensures some private device * data is setup before we export) */ -- cgit v0.10.2 From d8ee4ea68ff9c0f13646070aeada668a4eae9189 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:20 +0300 Subject: serial: omap: don't access the platform_device The driver doesn't need to know about its platform_device. Everything the driver needs can be done through the struct device pointer. In case we need to use the OMAP-specific PM function pointers, those can make sure to find the device's platform_device pointer so they can find the struct omap_device through pdev->archdata field. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index 25d53b2..9e80d20 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -81,8 +81,9 @@ static struct omap_uart_port_info omap_serial_default_info[] __initdata = { }; #ifdef CONFIG_PM -static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable) +static void omap_uart_enable_wakeup(struct device *dev, bool enable) { + struct platform_device *pdev = to_platform_device(dev); struct omap_device *od = to_omap_device(pdev); if (!od) @@ -99,15 +100,17 @@ static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable) * in Smartidle Mode When Configured for DMA Operations. * WA: configure uart in force idle mode. */ -static void omap_uart_set_noidle(struct platform_device *pdev) +static void omap_uart_set_noidle(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct omap_device *od = to_omap_device(pdev); omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_NO); } -static void omap_uart_set_smartidle(struct platform_device *pdev) +static void omap_uart_set_smartidle(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct omap_device *od = to_omap_device(pdev); u8 idlemode; @@ -120,10 +123,10 @@ static void omap_uart_set_smartidle(struct platform_device *pdev) } #else -static void omap_uart_enable_wakeup(struct platform_device *pdev, bool enable) +static void omap_uart_enable_wakeup(struct device *dev, bool enable) {} -static void omap_uart_set_noidle(struct platform_device *pdev) {} -static void omap_uart_set_smartidle(struct platform_device *pdev) {} +static void omap_uart_set_noidle(struct device *dev) {} +static void omap_uart_set_smartidle(struct device *dev) {} #endif /* CONFIG_PM */ #ifdef CONFIG_OMAP_MUX diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 5cc0626..90d2d74 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -18,7 +18,7 @@ #define __OMAP_SERIAL_H__ #include -#include +#include #include #include @@ -74,9 +74,9 @@ struct omap_uart_port_info { int DTR_present; int (*get_context_loss_count)(struct device *); - void (*set_forceidle)(struct platform_device *); - void (*set_noidle)(struct platform_device *); - void (*enable_wakeup)(struct platform_device *, bool); + void (*set_forceidle)(struct device *); + void (*set_noidle)(struct device *); + void (*enable_wakeup)(struct device *, bool); }; struct uart_omap_dma { @@ -108,7 +108,7 @@ struct uart_omap_dma { struct uart_omap_port { struct uart_port port; struct uart_omap_dma uart_dma; - struct platform_device *pdev; + struct device *dev; unsigned char ier; unsigned char lcr; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 3a60b86..5af5d22 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -104,36 +104,36 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up) static int serial_omap_get_context_loss_count(struct uart_omap_port *up) { - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + struct omap_uart_port_info *pdata = up->dev->platform_data; if (!pdata->get_context_loss_count) return 0; - return pdata->get_context_loss_count(&up->pdev->dev); + return pdata->get_context_loss_count(up->dev); } static void serial_omap_set_forceidle(struct uart_omap_port *up) { - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + struct omap_uart_port_info *pdata = up->dev->platform_data; if (pdata->set_forceidle) - pdata->set_forceidle(up->pdev); + pdata->set_forceidle(up->dev); } static void serial_omap_set_noidle(struct uart_omap_port *up) { - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + struct omap_uart_port_info *pdata = up->dev->platform_data; if (pdata->set_noidle) - pdata->set_noidle(up->pdev); + pdata->set_noidle(up->dev); } static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + struct omap_uart_port_info *pdata = up->dev->platform_data; if (pdata->enable_wakeup) - pdata->enable_wakeup(up->pdev, enable); + pdata->enable_wakeup(up->dev, enable); } /* @@ -169,8 +169,8 @@ static void serial_omap_stop_rxdma(struct uart_omap_port *up) omap_free_dma(up->uart_dma.rx_dma_channel); up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; up->uart_dma.rx_dma_used = false; - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } } @@ -180,16 +180,16 @@ static void serial_omap_enable_ms(struct uart_port *port) dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); } static void serial_omap_stop_tx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - struct omap_uart_port_info *pdata = up->pdev->dev.platform_data; + struct omap_uart_port_info *pdata = up->dev->platform_data; if (up->use_dma && up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) { @@ -202,11 +202,11 @@ static void serial_omap_stop_tx(struct uart_port *port) omap_stop_dma(up->uart_dma.tx_dma_channel); omap_free_dma(up->uart_dma.tx_dma_channel); up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); if (up->ier & UART_IER_THRI) { up->ier &= ~UART_IER_THRI; serial_out(up, UART_IER, up->ier); @@ -215,22 +215,22 @@ static void serial_omap_stop_tx(struct uart_port *port) if (!up->use_dma && pdata) serial_omap_set_forceidle(up); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_rx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); if (up->use_dma) serial_omap_stop_rxdma(up); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static inline void receive_chars(struct uart_omap_port *up, @@ -348,11 +348,11 @@ static void serial_omap_start_tx(struct uart_port *port) int ret = 0; if (!up->use_dma) { - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); serial_omap_enable_ier_thri(up); serial_omap_set_noidle(up); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); return; } @@ -362,7 +362,7 @@ static void serial_omap_start_tx(struct uart_port *port) xmit = &up->port.state->xmit; if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) { - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); ret = omap_request_dma(up->uart_dma.uart_dma_tx, "UART Tx DMA", (void *)uart_tx_dma_callback, up, @@ -445,11 +445,11 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) unsigned int iir, lsr; unsigned long flags; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) { - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); return IRQ_NONE; } @@ -473,8 +473,8 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) transmit_chars(up); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; return IRQ_HANDLED; @@ -486,12 +486,12 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port) unsigned long flags = 0; unsigned int ret = 0; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line); spin_lock_irqsave(&up->port.lock, flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); return ret; } @@ -501,9 +501,9 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) unsigned int status; unsigned int ret = 0; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); status = check_modem_status(up); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line); @@ -535,11 +535,11 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); up->mcr = serial_in(up, UART_MCR); up->mcr |= mcr; serial_out(up, UART_MCR, up->mcr); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); if (gpio_is_valid(up->DTR_gpio) && !!(mctrl & TIOCM_DTR) != up->DTR_active) { @@ -558,7 +558,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) unsigned long flags = 0; dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; @@ -566,7 +566,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); } static int serial_omap_startup(struct uart_port *port) @@ -585,7 +585,7 @@ static int serial_omap_startup(struct uart_port *port) dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) @@ -641,8 +641,8 @@ static int serial_omap_startup(struct uart_port *port) /* Enable module level wake up */ serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; return 0; } @@ -654,7 +654,7 @@ static void serial_omap_shutdown(struct uart_port *port) dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); /* * Disable interrupts from this port */ @@ -689,7 +689,7 @@ static void serial_omap_shutdown(struct uart_port *port) up->uart_dma.rx_buf = NULL; } - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); free_irq(up->port.irq, up); } @@ -821,7 +821,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); /* @@ -970,7 +970,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_omap_configure_xonxoff(up, termios); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } @@ -983,7 +983,7 @@ serial_omap_pm(struct uart_port *port, unsigned int state, dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, efr | UART_EFR_ECB); @@ -994,14 +994,14 @@ serial_omap_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - if (!device_may_wakeup(&up->pdev->dev)) { + if (!device_may_wakeup(up->dev)) { if (!state) - pm_runtime_forbid(&up->pdev->dev); + pm_runtime_forbid(up->dev); else - pm_runtime_allow(&up->pdev->dev); + pm_runtime_allow(up->dev); } - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); } static void serial_omap_release_port(struct uart_port *port) @@ -1080,10 +1080,10 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) { struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); wait_for_xmitr(up); serial_out(up, UART_TX, ch); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); } static int serial_omap_poll_get_char(struct uart_port *port) @@ -1091,13 +1091,13 @@ static int serial_omap_poll_get_char(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); unsigned int status; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); status = serial_in(up, UART_LSR); if (!(status & UART_LSR_DR)) return NO_POLL_CHAR; status = serial_in(up, UART_RX); - pm_runtime_put(&up->pdev->dev); + pm_runtime_put(up->dev); return status; } @@ -1126,7 +1126,7 @@ serial_omap_console_write(struct console *co, const char *s, unsigned int ier; int locked = 1; - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); local_irq_save(flags); if (up->port.sysrq) @@ -1160,8 +1160,8 @@ serial_omap_console_write(struct console *co, const char *s, if (up->msr_saved_flags) check_modem_status(up); - pm_runtime_mark_last_busy(&up->pdev->dev); - pm_runtime_put_autosuspend(&up->pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); if (locked) spin_unlock(&up->port.lock); local_irq_restore(flags); @@ -1323,7 +1323,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up) int ret = 0; if (up->uart_dma.rx_dma_channel == -1) { - pm_runtime_get_sync(&up->pdev->dev); + pm_runtime_get_sync(up->dev); ret = omap_request_dma(up->uart_dma.uart_dma_rx, "UART Rx DMA", (void *)uart_rx_dma_callback, up, @@ -1435,7 +1435,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up) minor = (mvr & OMAP_UART_MVR_MIN_MASK); break; default: - dev_warn(&up->pdev->dev, + dev_warn(up->dev, "Unknown %s revision, defaulting to highest\n", up->name); /* highest possible revision */ @@ -1535,7 +1535,7 @@ static int serial_omap_probe(struct platform_device *pdev) up->DTR_gpio = -EINVAL; up->DTR_active = 0; - up->pdev = pdev; + up->dev = &pdev->dev; up->port.dev = &pdev->dev; up->port.type = PORT_OMAP; up->port.iotype = UPIO_MEM; @@ -1632,7 +1632,7 @@ static int serial_omap_remove(struct platform_device *dev) struct uart_omap_port *up = platform_get_drvdata(dev); if (up) { - pm_runtime_disable(&up->pdev->dev); + pm_runtime_disable(up->dev); uart_remove_one_port(&serial_omap_reg, &up->port); pm_qos_remove_request(&up->pm_qos_request); } @@ -1667,7 +1667,7 @@ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1) timeout--; if (!timeout) { /* Should *never* happen. we warn and carry on */ - dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n", + dev_crit(up->dev, "Errata i202: timedout %x\n", serial_in(up, UART_LSR)); break; } -- cgit v0.10.2 From 494574304711a333386e7dd5fd3ebbc3b7024994 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:21 +0300 Subject: serial: omap: drop DMA support The current support is known to be broken and a later patch will come re-adding it using dma engine API. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 5af5d22..dd3971f 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include -#include #include #include @@ -75,9 +73,6 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ -static void uart_tx_dma_callback(int lch, u16 ch_status, void *data); -static void serial_omap_rxdma_poll(unsigned long uart_no); -static int serial_omap_start_rxdma(struct uart_omap_port *up); static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1); static struct workqueue_struct *serial_omap_uart_wq; @@ -161,19 +156,6 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud) return port->uartclk/(baud * divisor); } -static void serial_omap_stop_rxdma(struct uart_omap_port *up) -{ - if (up->uart_dma.rx_dma_used) { - del_timer(&up->uart_dma.rx_timer); - omap_stop_dma(up->uart_dma.rx_dma_channel); - omap_free_dma(up->uart_dma.rx_dma_channel); - up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; - up->uart_dma.rx_dma_used = false; - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - } -} - static void serial_omap_enable_ms(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); @@ -189,22 +171,6 @@ static void serial_omap_enable_ms(struct uart_port *port) static void serial_omap_stop_tx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - struct omap_uart_port_info *pdata = up->dev->platform_data; - - if (up->use_dma && - up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) { - /* - * Check if dma is still active. If yes do nothing, - * return. Else stop dma - */ - if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel)) - return; - omap_stop_dma(up->uart_dma.tx_dma_channel); - omap_free_dma(up->uart_dma.tx_dma_channel); - up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - } pm_runtime_get_sync(up->dev); if (up->ier & UART_IER_THRI) { @@ -212,8 +178,7 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } - if (!up->use_dma && pdata) - serial_omap_set_forceidle(up); + serial_omap_set_forceidle(up); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); @@ -224,8 +189,6 @@ static void serial_omap_stop_rx(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); pm_runtime_get_sync(up->dev); - if (up->use_dma) - serial_omap_stop_rxdma(up); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); @@ -343,67 +306,12 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up) static void serial_omap_start_tx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - struct circ_buf *xmit; - unsigned int start; - int ret = 0; - - if (!up->use_dma) { - pm_runtime_get_sync(up->dev); - serial_omap_enable_ier_thri(up); - serial_omap_set_noidle(up); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - return; - } - - if (up->uart_dma.tx_dma_used) - return; - - xmit = &up->port.state->xmit; - - if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) { - pm_runtime_get_sync(up->dev); - ret = omap_request_dma(up->uart_dma.uart_dma_tx, - "UART Tx DMA", - (void *)uart_tx_dma_callback, up, - &(up->uart_dma.tx_dma_channel)); - if (ret < 0) { - serial_omap_enable_ier_thri(up); - return; - } - } - spin_lock(&(up->uart_dma.tx_lock)); - up->uart_dma.tx_dma_used = true; - spin_unlock(&(up->uart_dma.tx_lock)); - - start = up->uart_dma.tx_buf_dma_phys + - (xmit->tail & (UART_XMIT_SIZE - 1)); - - up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); - /* - * It is a circular buffer. See if the buffer has wounded back. - * If yes it will have to be transferred in two separate dma - * transfers - */ - if (start + up->uart_dma.tx_buf_size >= - up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - up->uart_dma.tx_buf_size = - (up->uart_dma.tx_buf_dma_phys + - UART_XMIT_SIZE) - start; - - omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - up->uart_dma.uart_base, 0, 0); - omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_POST_INC, start, 0, 0); - omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, - OMAP_DMA_DATA_TYPE_S8, - up->uart_dma.tx_buf_size, 1, - OMAP_DMA_SYNC_ELEMENT, - up->uart_dma.uart_dma_tx, 0); - /* FIXME: Cache maintenance needed here? */ - omap_start_dma(up->uart_dma.tx_dma_channel); + pm_runtime_get_sync(up->dev); + serial_omap_enable_ier_thri(up); + serial_omap_set_noidle(up); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static unsigned int check_modem_status(struct uart_omap_port *up) @@ -456,16 +364,8 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) spin_lock_irqsave(&up->port.lock, flags); lsr = serial_in(up, UART_LSR); if (iir & UART_IIR_RLSI) { - if (!up->use_dma) { - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr); - } else { - up->ier &= ~(UART_IER_RDI | UART_IER_RLSI); - serial_out(up, UART_IER, up->ier); - if ((serial_omap_start_rxdma(up) != 0) && - (lsr & UART_LSR_DR)) - receive_chars(up, &lsr); - } + if (lsr & UART_LSR_DR) + receive_chars(up, &lsr); } check_modem_status(up); @@ -616,20 +516,6 @@ static int serial_omap_startup(struct uart_port *port) spin_unlock_irqrestore(&up->port.lock, flags); up->msr_saved_flags = 0; - if (up->use_dma) { - free_page((unsigned long)up->port.state->xmit.buf); - up->port.state->xmit.buf = dma_alloc_coherent(NULL, - UART_XMIT_SIZE, - (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), - 0); - init_timer(&(up->uart_dma.rx_timer)); - up->uart_dma.rx_timer.function = serial_omap_rxdma_poll; - up->uart_dma.rx_timer.data = up->port.line; - /* Currently the buffer size is 4KB. Can increase it */ - up->uart_dma.rx_buf = dma_alloc_coherent(NULL, - up->uart_dma.rx_buf_size, - (dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0); - } /* * Finally, enable interrupts. Note: Modem status interrupts * are set via set_termios(), which will be occurring imminently @@ -677,17 +563,6 @@ static void serial_omap_shutdown(struct uart_port *port) */ if (serial_in(up, UART_LSR) & UART_LSR_DR) (void) serial_in(up, UART_RX); - if (up->use_dma) { - dma_free_coherent(up->port.dev, - UART_XMIT_SIZE, up->port.state->xmit.buf, - up->uart_dma.tx_buf_dma_phys); - up->port.state->xmit.buf = NULL; - serial_omap_stop_rx(port); - dma_free_coherent(up->port.dev, - up->uart_dma.rx_buf_size, up->uart_dma.rx_buf, - up->uart_dma.rx_buf_dma_phys); - up->uart_dma.rx_buf = NULL; - } pm_runtime_put(up->dev); free_irq(up->port.irq, up); @@ -814,8 +689,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 | UART_FCR_ENABLE_FIFO; - if (up->use_dma) - up->fcr |= UART_FCR_DMA_SELECT; /* * Ok, we're now changing the port state. Do it with @@ -891,14 +764,9 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; - if (up->use_dma) { - serial_out(up, UART_TI752_TLR, 0); - up->scr |= UART_FCR_TRIGGER_4; - } else { - /* Set receive FIFO threshold to 1 byte */ - up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; - up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT); - } + /* Set receive FIFO threshold to 1 byte */ + up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; + up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT); serial_out(up, UART_FCR, up->fcr); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); @@ -1267,149 +1135,6 @@ static int serial_omap_resume(struct device *dev) } #endif -static void serial_omap_rxdma_poll(unsigned long uart_no) -{ - struct uart_omap_port *up = ui[uart_no]; - unsigned int curr_dma_pos, curr_transmitted_size; - int ret = 0; - - curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel); - if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || - (curr_dma_pos == 0)) { - if (jiffies_to_msecs(jiffies - up->port_activity) < - up->uart_dma.rx_timeout) { - mod_timer(&up->uart_dma.rx_timer, jiffies + - usecs_to_jiffies(up->uart_dma.rx_poll_rate)); - } else { - serial_omap_stop_rxdma(up); - up->ier |= (UART_IER_RDI | UART_IER_RLSI); - serial_out(up, UART_IER, up->ier); - } - return; - } - - curr_transmitted_size = curr_dma_pos - - up->uart_dma.prev_rx_dma_pos; - up->port.icount.rx += curr_transmitted_size; - tty_insert_flip_string(up->port.state->port.tty, - up->uart_dma.rx_buf + - (up->uart_dma.prev_rx_dma_pos - - up->uart_dma.rx_buf_dma_phys), - curr_transmitted_size); - tty_flip_buffer_push(up->port.state->port.tty); - up->uart_dma.prev_rx_dma_pos = curr_dma_pos; - if (up->uart_dma.rx_buf_size + - up->uart_dma.rx_buf_dma_phys == curr_dma_pos) { - ret = serial_omap_start_rxdma(up); - if (ret < 0) { - serial_omap_stop_rxdma(up); - up->ier |= (UART_IER_RDI | UART_IER_RLSI); - serial_out(up, UART_IER, up->ier); - } - } else { - mod_timer(&up->uart_dma.rx_timer, jiffies + - usecs_to_jiffies(up->uart_dma.rx_poll_rate)); - } - up->port_activity = jiffies; -} - -static void uart_rx_dma_callback(int lch, u16 ch_status, void *data) -{ - return; -} - -static int serial_omap_start_rxdma(struct uart_omap_port *up) -{ - int ret = 0; - - if (up->uart_dma.rx_dma_channel == -1) { - pm_runtime_get_sync(up->dev); - ret = omap_request_dma(up->uart_dma.uart_dma_rx, - "UART Rx DMA", - (void *)uart_rx_dma_callback, up, - &(up->uart_dma.rx_dma_channel)); - if (ret < 0) - return ret; - - omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - up->uart_dma.uart_base, 0, 0); - omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0, - OMAP_DMA_AMODE_POST_INC, - up->uart_dma.rx_buf_dma_phys, 0, 0); - omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel, - OMAP_DMA_DATA_TYPE_S8, - up->uart_dma.rx_buf_size, 1, - OMAP_DMA_SYNC_ELEMENT, - up->uart_dma.uart_dma_rx, 0); - } - up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys; - /* FIXME: Cache maintenance needed here? */ - omap_start_dma(up->uart_dma.rx_dma_channel); - mod_timer(&up->uart_dma.rx_timer, jiffies + - usecs_to_jiffies(up->uart_dma.rx_poll_rate)); - up->uart_dma.rx_dma_used = true; - return ret; -} - -static void serial_omap_continue_tx(struct uart_omap_port *up) -{ - struct circ_buf *xmit = &up->port.state->xmit; - unsigned int start = up->uart_dma.tx_buf_dma_phys - + (xmit->tail & (UART_XMIT_SIZE - 1)); - - if (uart_circ_empty(xmit)) - return; - - up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit); - /* - * It is a circular buffer. See if the buffer has wounded back. - * If yes it will have to be transferred in two separate dma - * transfers - */ - if (start + up->uart_dma.tx_buf_size >= - up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - up->uart_dma.tx_buf_size = - (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start; - omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_CONSTANT, - up->uart_dma.uart_base, 0, 0); - omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0, - OMAP_DMA_AMODE_POST_INC, start, 0, 0); - omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel, - OMAP_DMA_DATA_TYPE_S8, - up->uart_dma.tx_buf_size, 1, - OMAP_DMA_SYNC_ELEMENT, - up->uart_dma.uart_dma_tx, 0); - /* FIXME: Cache maintenance needed here? */ - omap_start_dma(up->uart_dma.tx_dma_channel); -} - -static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) -{ - struct uart_omap_port *up = data; - struct circ_buf *xmit = &up->port.state->xmit; - - xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \ - (UART_XMIT_SIZE - 1); - up->port.icount.tx += up->uart_dma.tx_buf_size; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - - if (uart_circ_empty(xmit)) { - spin_lock(&(up->uart_dma.tx_lock)); - serial_omap_stop_tx(&up->port); - up->uart_dma.tx_dma_used = false; - spin_unlock(&(up->uart_dma.tx_lock)); - } else { - omap_stop_dma(up->uart_dma.tx_dma_channel); - serial_omap_continue_tx(up); - } - up->port_activity = jiffies; - return; -} - static void omap_serial_fill_features_erratas(struct uart_omap_port *up) { u32 mvr, scheme; @@ -1479,7 +1204,7 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) static int serial_omap_probe(struct platform_device *pdev) { struct uart_omap_port *up; - struct resource *mem, *irq, *dma_tx, *dma_rx; + struct resource *mem, *irq; struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; int ret; @@ -1504,14 +1229,6 @@ static int serial_omap_probe(struct platform_device *pdev) return -EBUSY; } - dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!dma_rx) - return -ENXIO; - - dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!dma_tx) - return -ENXIO; - if (gpio_is_valid(omap_up_info->DTR_gpio) && omap_up_info->DTR_present) { ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial"); @@ -1574,20 +1291,6 @@ static int serial_omap_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "No clock speed specified: using default:" "%d\n", DEFAULT_CLK_SPEED); } - up->uart_dma.uart_base = mem->start; - - if (omap_up_info->dma_enabled) { - up->uart_dma.uart_dma_tx = dma_tx->start; - up->uart_dma.uart_dma_rx = dma_rx->start; - up->use_dma = 1; - up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size; - up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout; - up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate; - spin_lock_init(&(up->uart_dma.tx_lock)); - spin_lock_init(&(up->uart_dma.rx_lock)); - up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; - up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; - } up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; @@ -1730,10 +1433,6 @@ static int serial_omap_runtime_suspend(struct device *dev) } } - /* Errata i291 */ - if (up->use_dma && (up->errata & UART_ERRATA_i291_DMA_FORCEIDLE)) - serial_omap_set_forceidle(up); - up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&up->qos_work); @@ -1751,11 +1450,6 @@ static int serial_omap_runtime_resume(struct device *dev) if (up->context_loss_cnt != loss_cnt) serial_omap_restore_context(up); - /* Errata i291 */ - if ((up->errata & UART_ERRATA_i291_DMA_FORCEIDLE) && - up->use_dma) - serial_omap_set_noidle(up); - up->latency = up->calc_latency; schedule_work(&up->qos_work); } -- cgit v0.10.2 From a0f38b87de1df05acf2e3cc23ee2f02a18d80c85 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:22 +0300 Subject: serial: add OMAP-specific defines OMAP has some extra Interrupt types which can be really useful for SW. Let's define them so we can later use those in OMAP's serial driver. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h index 8ce70d7..5ed325e 100644 --- a/include/linux/serial_reg.h +++ b/include/linux/serial_reg.h @@ -40,6 +40,10 @@ #define UART_IIR_BUSY 0x07 /* DesignWare APB Busy Detect */ +#define UART_IIR_RX_TIMEOUT 0x0c /* OMAP RX Timeout interrupt */ +#define UART_IIR_XOFF 0x10 /* OMAP XOFF/Special Character */ +#define UART_IIR_CTS_RTS_DSR 0x20 /* OMAP CTS/RTS/DSR Change */ + #define UART_FCR 2 /* Out: FIFO Control Register */ #define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */ #define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */ -- cgit v0.10.2 From 81b75aef11abfd7b51e719a5388189eefa82e997 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:23 +0300 Subject: serial: omap: simplify IRQ handling quite a few changes here, though they are pretty obvious. In summary we're making sure to detect which interrupt type we need to handle before calling the underlying interrupt handling procedure. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index dd3971f..d5a08cb 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -351,33 +351,58 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; unsigned int iir, lsr; + unsigned int type; unsigned long flags; + irqreturn_t ret = IRQ_NONE; + spin_lock_irqsave(&up->port.lock, flags); pm_runtime_get_sync(up->dev); iir = serial_in(up, UART_IIR); - if (iir & UART_IIR_NO_INT) { - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - return IRQ_NONE; - } +again: + if (iir & UART_IIR_NO_INT) + goto out; - spin_lock_irqsave(&up->port.lock, flags); + ret = IRQ_HANDLED; lsr = serial_in(up, UART_LSR); - if (iir & UART_IIR_RLSI) { + + /* extract IRQ type from IIR register */ + type = iir & 0x3e; + + switch (type) { + case UART_IIR_MSI: + check_modem_status(up); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + transmit_chars(up); + break; + case UART_IIR_RDI: if (lsr & UART_LSR_DR) receive_chars(up, &lsr); + break; + case UART_IIR_RLSI: + if (lsr & UART_LSR_BRK_ERROR_BITS) + receive_chars(up, &lsr); + break; + case UART_IIR_RX_TIMEOUT: + receive_chars(up, &lsr); + break; + case UART_IIR_CTS_RTS_DSR: + iir = serial_in(up, UART_IIR); + goto again; + case UART_IIR_XOFF: + /* FALLTHROUGH */ + default: + break; } - check_modem_status(up); - if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) - transmit_chars(up); - +out: spin_unlock_irqrestore(&up->port.lock, flags); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); - up->port_activity = jiffies; - return IRQ_HANDLED; + + return ret; } static unsigned int serial_omap_tx_empty(struct uart_port *port) -- cgit v0.10.2 From 72256cbd13904d4b4dbb16f5ec83a3293bb292c5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:24 +0300 Subject: serial: omap: refactor receive_chars() into rdi/rlsi handlers receive_chars() was getting too big and too difficult to follow. By splitting it into separate RDI and RSLI handlers, we have smaller functions which are easy to understand and only touch the pieces which they need to touch. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d5a08cb..9c0a4ae 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -196,74 +196,6 @@ static void serial_omap_stop_rx(struct uart_port *port) pm_runtime_put_autosuspend(up->dev); } -static inline void receive_chars(struct uart_omap_port *up, - unsigned int *status) -{ - struct tty_struct *tty = up->port.state->port.tty; - unsigned int flag, lsr = *status; - unsigned char ch = 0; - int max_count = 256; - - do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - /* - * For statistics only - */ - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) { - up->port.icount.parity++; - } else if (lsr & UART_LSR_FE) { - up->port.icount.frame++; - } - - if (lsr & UART_LSR_OE) - up->port.icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= up->port.read_status_mask; - -#ifdef CONFIG_SERIAL_OMAP_CONSOLE - if (up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - lsr |= up->lsr_break_flag; - } -#endif - if (lsr & UART_LSR_BI) - flag = TTY_BREAK; - else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } - - if (uart_handle_sysrq_char(&up->port, ch)) - goto ignore_char; - uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); -ignore_char: - lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); - spin_unlock(&up->port.lock); - tty_flip_buffer_push(tty); - spin_lock(&up->port.lock); -} - static void transmit_chars(struct uart_omap_port *up) { struct circ_buf *xmit = &up->port.state->xmit; @@ -342,6 +274,68 @@ static unsigned int check_modem_status(struct uart_omap_port *up) return status; } +static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) +{ + unsigned int flag; + + up->port.icount.rx++; + flag = TTY_NORMAL; + + if (lsr & UART_LSR_BI) { + flag = TTY_BREAK; + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + up->port.icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(&up->port)) + return; + + } + + if (lsr & UART_LSR_PE) { + flag = TTY_PARITY; + up->port.icount.parity++; + } + + if (lsr & UART_LSR_FE) { + flag = TTY_FRAME; + up->port.icount.frame++; + } + + if (lsr & UART_LSR_OE) + up->port.icount.overrun++; + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + lsr |= up->lsr_break_flag; + } +#endif + uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag); +} + +static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) +{ + unsigned char ch = 0; + unsigned int flag; + + if (!(lsr & UART_LSR_DR)) + return; + + ch = serial_in(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; + + if (uart_handle_sysrq_char(&up->port, ch)) + return; + + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); +} + /** * serial_omap_irq() - This handles the interrupt from one port * @irq: uart port irq number @@ -350,54 +344,57 @@ static unsigned int check_modem_status(struct uart_omap_port *up) static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; + struct tty_struct *tty = up->port.state->port.tty; unsigned int iir, lsr; unsigned int type; unsigned long flags; irqreturn_t ret = IRQ_NONE; + int max_count = 256; spin_lock_irqsave(&up->port.lock, flags); pm_runtime_get_sync(up->dev); - iir = serial_in(up, UART_IIR); -again: - if (iir & UART_IIR_NO_INT) - goto out; - ret = IRQ_HANDLED; - lsr = serial_in(up, UART_LSR); + do { + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) + break; - /* extract IRQ type from IIR register */ - type = iir & 0x3e; + ret = IRQ_HANDLED; + lsr = serial_in(up, UART_LSR); - switch (type) { - case UART_IIR_MSI: - check_modem_status(up); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) - transmit_chars(up); - break; - case UART_IIR_RDI: - if (lsr & UART_LSR_DR) - receive_chars(up, &lsr); - break; - case UART_IIR_RLSI: - if (lsr & UART_LSR_BRK_ERROR_BITS) - receive_chars(up, &lsr); - break; - case UART_IIR_RX_TIMEOUT: - receive_chars(up, &lsr); - break; - case UART_IIR_CTS_RTS_DSR: - iir = serial_in(up, UART_IIR); - goto again; - case UART_IIR_XOFF: - /* FALLTHROUGH */ - default: - break; - } + /* extract IRQ type from IIR register */ + type = iir & 0x3e; + + switch (type) { + case UART_IIR_MSI: + check_modem_status(up); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) + transmit_chars(up); + break; + case UART_IIR_RX_TIMEOUT: + /* FALLTHROUGH */ + case UART_IIR_RDI: + serial_omap_rdi(up, lsr); + break; + case UART_IIR_RLSI: + serial_omap_rlsi(up, lsr); + break; + case UART_IIR_CTS_RTS_DSR: + /* simply try again */ + break; + case UART_IIR_XOFF: + /* FALLTHROUGH */ + default: + break; + } + } while (!(iir & UART_IIR_NO_INT) && max_count--); -out: spin_unlock_irqrestore(&up->port.lock, flags); + + tty_flip_buffer_push(tty); + pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; -- cgit v0.10.2 From bf63a0862c964f9015d0d8e3c2ccca7005eebea2 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:25 +0300 Subject: serial: omap: move THRE check to transmit_chars() since all other IRQ types now do all necessary checks inside their handlers, transmit_chars() was the only one left expecting serial_omap_irq() to check THRE for it. We can move THRE check to transmit_chars() in order to make serial_omap_irq() more uniform. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 9c0a4ae..d3fbb70 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -196,11 +196,14 @@ static void serial_omap_stop_rx(struct uart_port *port) pm_runtime_put_autosuspend(up->dev); } -static void transmit_chars(struct uart_omap_port *up) +static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) { struct circ_buf *xmit = &up->port.state->xmit; int count; + if (!(lsr & UART_LSR_THRE)) + return; + if (up->port.x_char) { serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; @@ -370,8 +373,7 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) check_modem_status(up); break; case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) - transmit_chars(up); + transmit_chars(up, lsr); break; case UART_IIR_RX_TIMEOUT: /* FALLTHROUGH */ -- cgit v0.10.2 From 660ac5f48a64026ad54c77d06f8360544e84dc84 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:26 +0300 Subject: serial: omap: stick to put_autosuspend Everytime we're done using our TTY, we want the pm timer to be reinitilized. By sticking to pm_runtime_pm_autosuspend() we make sure that this will always be the case. The idea behind this patch is to make sure we will always reinitialize the pm timer so that we don't fall into a situation where pm_runtime_put() expires right away (if timer was already about to expire when we made the call to pm_runtime_put()). While suspending right away wouldn't cause any issues, reinitializing the pm timer can help us avoiding unnecessary context save & restore operations (which are somewhat expensive) if there's another read/write/set_termios request coming right after. IOW, we are trying to make sure UART is still powered up while it's still under heavy usage. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d3fbb70..b2043df 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -165,7 +165,8 @@ static void serial_omap_enable_ms(struct uart_port *port) pm_runtime_get_sync(up->dev); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_tx(struct uart_port *port) @@ -415,7 +416,8 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port) spin_lock_irqsave(&up->port.lock, flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); return ret; } @@ -427,7 +429,8 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) pm_runtime_get_sync(up->dev); status = check_modem_status(up); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line); @@ -463,7 +466,8 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) up->mcr = serial_in(up, UART_MCR); up->mcr |= mcr; serial_out(up, UART_MCR, up->mcr); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); if (gpio_is_valid(up->DTR_gpio) && !!(mctrl & TIOCM_DTR) != up->DTR_active) { @@ -490,7 +494,8 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static int serial_omap_startup(struct uart_port *port) @@ -588,7 +593,8 @@ static void serial_omap_shutdown(struct uart_port *port) if (serial_in(up, UART_LSR) & UART_LSR_DR) (void) serial_in(up, UART_RX); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); free_irq(up->port.irq, up); } @@ -862,7 +868,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_omap_configure_xonxoff(up, termios); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } @@ -893,7 +900,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state, pm_runtime_allow(up->dev); } - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static void serial_omap_release_port(struct uart_port *port) @@ -975,7 +983,8 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) pm_runtime_get_sync(up->dev); wait_for_xmitr(up); serial_out(up, UART_TX, ch); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); } static int serial_omap_poll_get_char(struct uart_port *port) @@ -989,7 +998,8 @@ static int serial_omap_poll_get_char(struct uart_port *port) return NO_POLL_CHAR; status = serial_in(up, UART_RX); - pm_runtime_put(up->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); return status; } @@ -1340,7 +1350,8 @@ static int serial_omap_probe(struct platform_device *pdev) if (ret != 0) goto err_add_port; - pm_runtime_put(&pdev->dev); + pm_runtime_mark_last_busy(up->dev); + pm_runtime_put_autosuspend(up->dev); platform_set_drvdata(pdev, up); return 0; -- cgit v0.10.2 From 93220dcc3052182e7156c09655ad1316055564b9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:27 +0300 Subject: serial: omap: set dev->drvdata before enabling pm_runtime by the time we call our first pm_runtme_get_sync() after enable pm_runtime, our resume method might be called. To avoid problems, we must make sure that our dev->drvdata is set correctly before our resume method gets called. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index b2043df..8a696a4 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1333,6 +1333,7 @@ static int serial_omap_probe(struct platform_device *pdev) serial_omap_uart_wq = create_singlethread_workqueue(up->name); INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); + platform_set_drvdata(pdev, up); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, omap_up_info->autosuspend_timeout); @@ -1352,7 +1353,6 @@ static int serial_omap_probe(struct platform_device *pdev) pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); - platform_set_drvdata(pdev, up); return 0; err_add_port: -- cgit v0.10.2 From 1b42c8b29b1822436e690fd0a7906aaa62099f91 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:28 +0300 Subject: serial: omap: drop unnecessary check from remove if platform_get_drvdata() returns NULL, that's quite a nasty bug on the driver which we want to catch ASAP. Otherwise, that check is hugely unneeded. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 8a696a4..c19d340 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1369,13 +1369,10 @@ static int serial_omap_remove(struct platform_device *dev) { struct uart_omap_port *up = platform_get_drvdata(dev); - if (up) { - pm_runtime_disable(up->dev); - uart_remove_one_port(&serial_omap_reg, &up->port); - pm_qos_remove_request(&up->pm_qos_request); - } + pm_runtime_disable(up->dev); + uart_remove_one_port(&serial_omap_reg, &up->port); + pm_qos_remove_request(&up->pm_qos_request); - platform_set_drvdata(dev, NULL); return 0; } -- cgit v0.10.2 From 7e9c8e7dbf3b9cc94947d76cb57985682517cc6e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:29 +0300 Subject: serial: omap: make sure to suspend device before remove before removing the driver, let's make sure to force device into a suspended state in order to conserve power. Tested-by: Shubhrajyoti D Acked-by: Santosh Shilimkar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index c19d340..0ceca44 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1369,6 +1369,7 @@ static int serial_omap_remove(struct platform_device *dev) { struct uart_omap_port *up = platform_get_drvdata(dev); + pm_runtime_put_sync(up->dev); pm_runtime_disable(up->dev); uart_remove_one_port(&serial_omap_reg, &up->port); pm_qos_remove_request(&up->pm_qos_request); -- cgit v0.10.2 From 6c3a30c7fbed820f65d5e708f1e83468d8ec9921 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:30 +0300 Subject: serial: omap: don't save IRQ flags on hardirq When we're running our hardirq handler, there's not need to disable IRQs with spin_lock_irqsave() because IRQs are already disabled. It also makes no difference if we save or not IRQ flags. Switch over to simple spin_lock/spin_unlock and drop the "flags" variable. Tested-by: Shubhrajyoti D Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 0ceca44..99042b0 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -351,11 +351,10 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) struct tty_struct *tty = up->port.state->port.tty; unsigned int iir, lsr; unsigned int type; - unsigned long flags; irqreturn_t ret = IRQ_NONE; int max_count = 256; - spin_lock_irqsave(&up->port.lock, flags); + spin_lock(&up->port.lock); pm_runtime_get_sync(up->dev); do { @@ -394,7 +393,7 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) } } while (!(iir & UART_IIR_NO_INT) && max_count--); - spin_unlock_irqrestore(&up->port.lock, flags); + spin_unlock(&up->port.lock); tty_flip_buffer_push(tty); -- cgit v0.10.2 From 856e35bf596e83a63c8a9ec749e9f2bcd24a1bdd Mon Sep 17 00:00:00 2001 From: Ruchika Kharwar Date: Thu, 6 Sep 2012 15:45:31 +0300 Subject: serial: omap: fix sequence of pm_runtime_* calls. pm_runtime_enable() needs to be invoked before pm_runtime_use_autosuspend(), and pm_runtime_set_autosuspend_delay() functions. Tested-by: Shubhrajyoti D Signed-off-by: Nishanth Menon Signed-off-by: Ruchika Kharwar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 99042b0..f5dcb5a 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1333,12 +1333,12 @@ static int serial_omap_probe(struct platform_device *pdev) INIT_WORK(&up->qos_work, serial_omap_uart_qos_work); platform_set_drvdata(pdev, up); + pm_runtime_enable(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, omap_up_info->autosuspend_timeout); pm_runtime_irq_safe(&pdev->dev); - pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); omap_serial_fill_features_erratas(up); -- cgit v0.10.2 From 6d608ef351bbd0b49427b5b6c6ec6d7622bc0d22 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:32 +0300 Subject: serial: omap: optimization with section annotations Two functions: omap_serial_fill_features_erratas() and of_get_uart_port_info() are only called from probe(). Marking them as __devinit gives us another oportunity to free some code after .init.text is done. Tested-by: Shubhrajyoti D Signed-off-by: Ruchika Kharwar Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index f5dcb5a..9068260 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1168,7 +1168,7 @@ static int serial_omap_resume(struct device *dev) } #endif -static void omap_serial_fill_features_erratas(struct uart_omap_port *up) +static void __devinit omap_serial_fill_features_erratas(struct uart_omap_port *up) { u32 mvr, scheme; u16 revision, major, minor; @@ -1221,7 +1221,7 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up) } } -static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) +static __devinit struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) { struct omap_uart_port_info *omap_up_info; @@ -1234,7 +1234,7 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) return omap_up_info; } -static int serial_omap_probe(struct platform_device *pdev) +static int __devinit serial_omap_probe(struct platform_device *pdev) { struct uart_omap_port *up; struct resource *mem, *irq; @@ -1364,7 +1364,7 @@ err_port_line: return ret; } -static int serial_omap_remove(struct platform_device *dev) +static int __devexit serial_omap_remove(struct platform_device *dev) { struct uart_omap_port *up = platform_get_drvdata(dev); @@ -1508,7 +1508,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match); static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, - .remove = serial_omap_remove, + .remove = __devexit_p(serial_omap_remove), .driver = { .name = DRIVER_NAME, .pm = &serial_omap_dev_pm_ops, -- cgit v0.10.2 From 52c5513d5925554d1e22288525bcb7d25fa98b16 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:33 +0300 Subject: serial: omap: drop "inline" from IRQ handler prototype it makes no sense to mark our IRQ handler inline since it's passed as a function pointer when enabling the IRQ line. Tested-by: Shubhrajyoti D Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 9068260..d244163 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -345,7 +345,7 @@ static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) * @irq: uart port irq number * @dev_id: uart port info */ -static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) +static irqreturn_t serial_omap_irq(int irq, void *dev_id) { struct uart_omap_port *up = dev_id; struct tty_struct *tty = up->port.state->port.tty; -- cgit v0.10.2 From 0324a821029e1f54e7a7f8fed48693cfce42dc0e Mon Sep 17 00:00:00 2001 From: Ruchika Kharwar Date: Thu, 6 Sep 2012 15:45:34 +0300 Subject: serial: omap: unlock the port lock This patch unlocks the port lock before calling a serial_core API and re-acquires the port lock after calling it. This patch fixes a system freeze issue seen when the serial_core API uart_write_wakeup() eventually attempts to acquire the port lock already acquired by omap serial interrupt handler. Tested-by: Shubhrajyoti D Signed-off-by: Ruchika Kharwar Signed-off-by: Pavan Savoy Signed-off-by: Vijay Badawadagi Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d244163..9e4419c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -224,8 +224,11 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) break; } while (--count > 0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { + spin_unlock(&up->port.lock); uart_write_wakeup(&up->port); + spin_lock(&up->port.lock); + } if (uart_circ_empty(xmit)) serial_omap_stop_tx(&up->port); -- cgit v0.10.2 From 9727faf4706eb49ce88e3f2bb961278a84eac080 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:35 +0300 Subject: serial: omap: implement set_wake This has been missing from OMAP UART driver for quite a while and it's simple enough to implement it. Tested-by: Shubhrajyoti D Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 9e4419c..7531147 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -875,6 +875,15 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } +static int serial_omap_set_wake(struct uart_port *port, unsigned int state) +{ + struct uart_omap_port *up = to_uart_omap_port(port); + + serial_omap_enable_wakeup(up, state); + + return 0; +} + static void serial_omap_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) @@ -1129,6 +1138,7 @@ static struct uart_ops serial_omap_pops = { .shutdown = serial_omap_shutdown, .set_termios = serial_omap_set_termios, .pm = serial_omap_pm, + .set_wake = serial_omap_set_wake, .type = serial_omap_type, .release_port = serial_omap_release_port, .request_port = serial_omap_request_port, -- cgit v0.10.2 From a6b19c333c2f100f32e07d5209cf9f0b4f81b6eb Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:36 +0300 Subject: serial: omap: make sure to put() on poll_get_char if we would reach serial_omap_get_char() while Data Ready bit isn't set, we would return from it without kicking our pm timer. This would mean we would, eventually, have an unbalanced pm_runtime_get on our device which would prevent it from ever sleeping again. Tested-by: Shubhrajyoti D Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 7531147..6a58f4f 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1005,12 +1005,17 @@ static int serial_omap_poll_get_char(struct uart_port *port) pm_runtime_get_sync(up->dev); status = serial_in(up, UART_LSR); - if (!(status & UART_LSR_DR)) - return NO_POLL_CHAR; + if (!(status & UART_LSR_DR)) { + status = NO_POLL_CHAR; + goto out; + } status = serial_in(up, UART_RX); + +out: pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); + return status; } -- cgit v0.10.2 From 957ee7270d632245b43f6feb0e70d9a5e9ea6cf6 Mon Sep 17 00:00:00 2001 From: Vikram Pandita Date: Thu, 6 Sep 2012 15:45:37 +0300 Subject: serial: omap: fix software flow control Software flow control register bits were not defined correctly. Also clarify the IXON and IXOFF logic to reflect what userspace wants. Cc: stable@vger.kernel.org Tested-by: Shubhrajyoti D Signed-off-by: Vikram Pandita Signed-off-by: Shubhrajyoti D Acked-by: Tony Lindgren Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 90d2d74..a79ed8b 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -42,10 +42,10 @@ #define OMAP_UART_WER_MOD_WKUP 0X7F /* Enable XON/XOFF flow control on output */ -#define OMAP_UART_SW_TX 0x04 +#define OMAP_UART_SW_TX 0x8 /* Enable XON/XOFF flow control on input */ -#define OMAP_UART_SW_RX 0x04 +#define OMAP_UART_SW_RX 0x2 #define OMAP_UART_SYSC_RESET 0X07 #define OMAP_UART_TCR_TRIG 0X0F diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 6a58f4f..1ba1f43 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -617,19 +617,19 @@ serial_omap_configure_xonxoff /* * IXON Flag: - * Enable XON/XOFF flow control on output. - * Transmit XON1, XOFF1 + * Flow control for OMAP.TX + * OMAP.RX should listen for XON/XOFF */ if (termios->c_iflag & IXON) - up->efr |= OMAP_UART_SW_TX; + up->efr |= OMAP_UART_SW_RX; /* * IXOFF Flag: - * Enable XON/XOFF flow control on input. - * Receiver compares XON1, XOFF1. + * Flow control for OMAP.RX + * OMAP.TX should send XON/XOFF */ if (termios->c_iflag & IXOFF) - up->efr |= OMAP_UART_SW_RX; + up->efr |= OMAP_UART_SW_TX; serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); -- cgit v0.10.2 From d21e4005e4a4c24939f239b49862e6b0852e9169 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:38 +0300 Subject: serial: omap: remove unnecessary header and add a missing one this driver doesn't use any from , so we can remove it without any problems. This will, however cause a problem because omap-serial.c was relying on indirect inclusion of , let's fix the issue by including on omap-serial.c as it should be. Tested-by: Shubhrajyoti D Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 1ba1f43..881b652 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include #include -#include #include #define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) -- cgit v0.10.2 From d37c6cebcb0c7ab4fc9e000061c93cca9d2a3941 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:39 +0300 Subject: serial: omap: move uart_omap_port definition to C file nobody needs to access the uart_omap_port structure other than omap-serial.c file. Let's move that structure definition to the C source file in order to prevent anyone from accessing our structure. Tested-by: Shubhrajyoti D Acked-by: Tony Lindgren Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index a79ed8b..3c9fd3e 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -105,45 +105,8 @@ struct uart_omap_dma { unsigned int rx_timeout; }; -struct uart_omap_port { - struct uart_port port; - struct uart_omap_dma uart_dma; - struct device *dev; - - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned char fcr; - unsigned char efr; - unsigned char dll; - unsigned char dlh; - unsigned char mdr1; - unsigned char scr; - - int use_dma; - /* - * Some bits in registers are cleared on a read, so they must - * be saved whenever the register is read but the bits will not - * be immediately processed. - */ - unsigned int lsr_break_flag; - unsigned char msr_saved_flags; - char name[20]; - unsigned long port_activity; - u32 context_loss_cnt; - u32 errata; - u8 wakeups_enabled; int DTR_gpio; int DTR_inverted; int DTR_active; - - struct pm_qos_request pm_qos_request; - u32 latency; - u32 calc_latency; - struct work_struct qos_work; -}; - -#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) - #endif /* __OMAP_SERIAL_H__ */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 881b652..164c3c9 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -70,6 +70,44 @@ #define OMAP_UART_MVR_MAJ_SHIFT 8 #define OMAP_UART_MVR_MIN_MASK 0x3f +struct uart_omap_port { + struct uart_port port; + struct uart_omap_dma uart_dma; + struct device *dev; + + unsigned char ier; + unsigned char lcr; + unsigned char mcr; + unsigned char fcr; + unsigned char efr; + unsigned char dll; + unsigned char dlh; + unsigned char mdr1; + unsigned char scr; + + int use_dma; + /* + * Some bits in registers are cleared on a read, so they must + * be saved whenever the register is read but the bits will not + * be immediately processed. + */ + unsigned int lsr_break_flag; + unsigned char msr_saved_flags; + char name[20]; + unsigned long port_activity; + u32 context_loss_cnt; + u32 errata; + u8 wakeups_enabled; + unsigned int irq_pending:1; + + struct pm_qos_request pm_qos_request; + u32 latency; + u32 calc_latency; + struct work_struct qos_work; +}; + +#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) + static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ -- cgit v0.10.2 From 6721ab7f77f2614ab43e3de2f908b1d7436331df Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Sep 2012 15:45:40 +0300 Subject: serial: omap: enable RX and TX FIFO usage enable RX FIFO for 16 characters and TX FIFO for 16 spaces. Tested-by: Shubhrajyoti D Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 164c3c9..cfd2094 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -56,8 +56,8 @@ #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7) /* FCR register bitmasks */ -#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) +#define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4) /* MVR register bitmasks */ #define OMAP_UART_MVR_SCHEME_SHIFT 30 @@ -834,9 +834,13 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; - /* Set receive FIFO threshold to 1 byte */ + /* Set receive FIFO threshold to 16 characters and + * transmit FIFO threshold to 16 spaces + */ up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; - up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT); + up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; + up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 | + UART_FCR_ENABLE_FIFO; serial_out(up, UART_FCR, up->fcr); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); -- cgit v0.10.2 From 37cd0c994fc8ecbfb258c4be2442d9d6f31447ea Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Thu, 6 Sep 2012 10:27:51 +0800 Subject: serial_core: fix sizeof(pointer) sizeof when applied to a pointer typed expression gives the size of the pointer. Generated by: scripts/coccinelle/misc/noderef.cocci Signed-off-by: Fengguang Wu Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 137b25c..19993d8 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -640,7 +640,7 @@ static void uart_get_info(struct tty_port *port, { struct uart_port *uport = state->uart_port; - memset(retinfo, 0, sizeof(retinfo)); + memset(retinfo, 0, sizeof(*retinfo)); retinfo->type = uport->type; retinfo->line = uport->line; -- cgit v0.10.2 From 851b714b29db0e394c293170e714f90a778060ad Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 6 Sep 2012 22:38:40 -0400 Subject: serial: mxs-auart: fix the wrong setting order After set the AUART_CTRL0_CLKGATE, the UART will gate all the clocks off. So the following line will not take effect. ................................................................ writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, u->membase + AUART_INTR_CLR); ................................................................ To fix this issue, the patch moves this gate-off line to the end of setting registers. Signed-off-by: Huang Shijie Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index dafeef2..ea5f888 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -457,11 +457,11 @@ static void mxs_auart_shutdown(struct uart_port *u) writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); - writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, u->membase + AUART_INTR_CLR); + writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); + clk_disable_unprepare(s->clk); } -- cgit v0.10.2 From b69200fbdf209f356f375da0cfd672f61c7a5866 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 6 Sep 2012 22:38:41 -0400 Subject: serial: mxs-auart: put the device in mxs_auart_probe() We call the get_device() in the mxs_auart_probe(). For the balance of the reference count, we should put the device in the mxs_auart_remove(). Signed-off-by: Huang Shijie Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index ea5f888..6898413 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -796,6 +796,7 @@ static int __devexit mxs_auart_remove(struct platform_device *pdev) auart_port[pdev->id] = NULL; + put_device(s->dev); clk_put(s->clk); free_irq(s->irq, s); kfree(s); -- cgit v0.10.2 From d83b54250988758cd3b9d21c242f98ae61fa1435 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 6 Sep 2012 15:05:04 +1000 Subject: serial: serial_core.h needs console.h included first Fixes these build errors: In file included from drivers/tty/serial/sccnxp.c:20:0: include/linux/serial_core.h: In function 'uart_handle_break': include/linux/serial_core.h:543:30: error: dereferencing pointer to incomplete type Signed-off-by: Stephen Rothwell Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 29dda9b..05d767c 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -17,12 +17,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include -- cgit v0.10.2 From 6915c0e487c822e2436683e14302c0b8a6155cc7 Mon Sep 17 00:00:00 2001 From: Tomas Hlavacek Date: Thu, 6 Sep 2012 03:17:18 +0200 Subject: tty: uartclk value from serial_core exposed to sysfs Added file /sys/devices/.../tty/ttySX/uartclk to allow reading uartclk value in struct uart_port in serial_core via sysfs. tty_register_device() has been generalized and refactored in order to add support for setting drvdata and attribute_group to the device. Signed-off-by: Tomas Hlavacek Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty index b138b66..0c43015 100644 --- a/Documentation/ABI/testing/sysfs-tty +++ b/Documentation/ABI/testing/sysfs-tty @@ -17,3 +17,12 @@ Description: device, like 'tty1'. The file supports poll() to detect virtual console switches. + +What: /sys/class/tty/ttyS0/uartclk +Date: Sep 2012 +Contact: Tomas Hlavacek +Description: + Shows the current uartclk value associated with the + UART port in serial_core, that is bound to TTY like ttyS0. + uartclk = 16 * baud_base + diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 19993d8..f629bdf 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2309,6 +2309,36 @@ struct tty_driver *uart_console_device(struct console *co, int *index) return p->tty_driver; } +static ssize_t uart_get_attr_uartclk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + mutex_lock(&state->port.mutex); + ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk); + mutex_unlock(&state->port.mutex); + + return ret; +} + +static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL); + +static struct attribute *tty_dev_attrs[] = { + &dev_attr_uartclk.attr, + NULL, + }; + +static struct attribute_group tty_dev_attr_group = { + .attrs = tty_dev_attrs, + }; + +static const struct attribute_group *tty_dev_attr_groups[] = { + &tty_dev_attr_group, + NULL + }; + /** * uart_add_one_port - attach a driver-defined port structure * @drv: pointer to the uart low level driver structure for this port @@ -2362,8 +2392,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_dev = tty_port_register_device(port, drv->tty_driver, uport->line, - uport->dev); + tty_dev = tty_register_device_attr(drv->tty_driver, uport->line, + uport->dev, port, tty_dev_attr_groups); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d3bf91a..dcb30d5 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3041,9 +3041,39 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev, struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { - struct device *ret; + return tty_register_device_attr(driver, index, device, NULL, NULL); +} +EXPORT_SYMBOL(tty_register_device); + +/** + * tty_register_device_attr - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to NULL safely. + * @drvdata: Driver data to be set to device. + * @attr_grp: Attribute group to be set on device. + * + * Returns a pointer to the struct device for this tty device + * (or ERR_PTR(-EFOO) on error). + * + * This call is required to be made to register an individual tty device + * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If + * that bit is not set, this function should not be called by a tty + * driver. + * + * Locking: ?? + */ +struct device *tty_register_device_attr(struct tty_driver *driver, + unsigned index, struct device *device, + void *drvdata, + const struct attribute_group **attr_grp) +{ char name[64]; - dev_t dev = MKDEV(driver->major, driver->minor_start) + index; + dev_t devt = MKDEV(driver->major, driver->minor_start) + index; + struct device *dev = NULL; + int retval = -ENODEV; bool cdev = false; if (index >= driver->num) { @@ -3058,19 +3088,38 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, tty_line_name(driver, index, name); if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { - int error = tty_cdev_add(driver, dev, index, 1); - if (error) - return ERR_PTR(error); + retval = tty_cdev_add(driver, devt, index, 1); + if (retval) + goto error; cdev = true; } - ret = device_create(tty_class, device, dev, NULL, name); - if (IS_ERR(ret) && cdev) - cdev_del(&driver->cdevs[index]); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto error; + } - return ret; + dev->devt = devt; + dev->class = tty_class; + dev->parent = device; + dev_set_name(dev, "%s", name); + dev->groups = attr_grp; + dev_set_drvdata(dev, drvdata); + + retval = device_register(dev); + if (retval) + goto error; + + return dev; + +error: + put_device(dev); + if (cdev) + cdev_del(&driver->cdevs[index]); + return ERR_PTR(retval); } -EXPORT_SYMBOL(tty_register_device); +EXPORT_SYMBOL_GPL(tty_register_device_attr); /** * tty_unregister_device - unregister a tty device diff --git a/include/linux/tty.h b/include/linux/tty.h index 9892121..599d603 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -412,6 +412,10 @@ extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); extern struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); +extern struct device *tty_register_device_attr(struct tty_driver *driver, + unsigned index, struct device *device, + void *drvdata, + const struct attribute_group **attr_grp); extern void tty_unregister_device(struct tty_driver *driver, unsigned index); extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen); -- cgit v0.10.2 From 80de7c3138ee9fd86a98696fd2cf7ad89b995d0a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 6 Sep 2012 12:01:00 -0400 Subject: Remove user-triggerable BUG from mpol_to_str Trivially triggerable, found by trinity: kernel BUG at mm/mempolicy.c:2546! Process trinity-child2 (pid: 23988, threadinfo ffff88010197e000, task ffff88007821a670) Call Trace: show_numa_map+0xd5/0x450 show_pid_numa_map+0x13/0x20 traverse+0xf2/0x230 seq_read+0x34b/0x3e0 vfs_read+0xac/0x180 sys_pread64+0xa2/0xc0 system_call_fastpath+0x1a/0x1f RIP: mpol_to_str+0x156/0x360 Cc: stable@vger.kernel.org Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds diff --git a/mm/mempolicy.c b/mm/mempolicy.c index bd92431..4ada3be 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2562,7 +2562,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context) break; default: - BUG(); + return -EINVAL; } l = strlen(policy_modes[mode]); -- cgit v0.10.2 From b1b799164afb22711e6bee718f2a5ee669bb9517 Mon Sep 17 00:00:00 2001 From: Tomas Hlavacek Date: Thu, 6 Sep 2012 23:17:47 +0200 Subject: tty_register_device_attr updated for tty-next Added tty_device_create_release() and bound to dev->release in tty_register_device_attr(). Added tty_port_register_device_attr() and used in uart_add_one_port() instead of tty_register_device_attr(). Signed-off-by: Tomas Hlavacek Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f629bdf..046279c 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2313,9 +2313,9 @@ static ssize_t uart_get_attr_uartclk(struct device *dev, struct device_attribute *attr, char *buf) { int ret; - struct tty_port *port = dev_get_drvdata(dev); struct uart_state *state = container_of(port, struct uart_state, port); + mutex_lock(&state->port.mutex); ret = snprintf(buf, PAGE_SIZE, "%d\n", state->uart_port->uartclk); mutex_unlock(&state->port.mutex); @@ -2330,7 +2330,7 @@ static struct attribute *tty_dev_attrs[] = { NULL, }; -static struct attribute_group tty_dev_attr_group = { +static const struct attribute_group tty_dev_attr_group = { .attrs = tty_dev_attrs, }; @@ -2392,8 +2392,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) * Register the port whether it's detected or not. This allows * setserial to be used to alter this ports parameters. */ - tty_dev = tty_register_device_attr(drv->tty_driver, uport->line, - uport->dev, port, tty_dev_attr_groups); + tty_dev = tty_port_register_device_attr(port, drv->tty_driver, + uport->line, uport->dev, port, tty_dev_attr_groups); if (likely(!IS_ERR(tty_dev))) { device_set_wakeup_capable(tty_dev, 1); } else { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index dcb30d5..8a5a8b0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3045,6 +3045,12 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, } EXPORT_SYMBOL(tty_register_device); +static void tty_device_create_release(struct device *dev) +{ + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); + kfree(dev); +} + /** * tty_register_device_attr - register a tty device * @driver: the tty driver that describes the tty device @@ -3103,6 +3109,7 @@ struct device *tty_register_device_attr(struct tty_driver *driver, dev->devt = devt; dev->class = tty_class; dev->parent = device; + dev->release = tty_device_create_release; dev_set_name(dev, "%s", name); dev->groups = attr_grp; dev_set_drvdata(dev, drvdata); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 96302f4..d7bdd8d 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -73,6 +73,30 @@ struct device *tty_port_register_device(struct tty_port *port, } EXPORT_SYMBOL_GPL(tty_port_register_device); +/** + * tty_port_register_device_attr - register tty device + * @port: tty_port of the device + * @driver: tty_driver for this device + * @index: index of the tty + * @device: parent if exists, otherwise NULL + * @drvdata: Driver data to be set to device. + * @attr_grp: Attribute group to be set on device. + * + * It is the same as tty_register_device_attr except the provided @port is + * linked to a concrete tty specified by @index. Use this or tty_port_install + * (or both). Call tty_port_link_device as a last resort. + */ +struct device *tty_port_register_device_attr(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device, void *drvdata, + const struct attribute_group **attr_grp) +{ + tty_port_link_device(port, driver, index); + return tty_register_device_attr(driver, index, device, drvdata, + attr_grp); +} +EXPORT_SYMBOL_GPL(tty_port_register_device_attr); + int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 599d603..1509b86 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -507,6 +507,10 @@ extern void tty_port_link_device(struct tty_port *port, extern struct device *tty_port_register_device(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device); +extern struct device *tty_port_register_device_attr(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device, void *drvdata, + const struct attribute_group **attr_grp); extern int tty_port_alloc_xmit_buf(struct tty_port *port); extern void tty_port_free_xmit_buf(struct tty_port *port); extern void tty_port_put(struct tty_port *port); -- cgit v0.10.2 From aad932e75c573aec37a0652ff1c27a975d8d5373 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Thu, 30 Aug 2012 14:37:14 +0200 Subject: HID: tpkbd: work even if the new Lenovo Keyboard driver is not configured c1dcad2d32d0252e8a3023d20311b52a187ecda3 added a new driver configured by HID_LENOVO_TPKBD but made the hid_have_special_driver entry non-optional which lead to a recognized but non-working device if the new driver wasn't configured (which is the correct default). Signed-off-by: Andres Freund Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b8485a0..8bcd168 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1559,7 +1559,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, +#if IS_ENABLED(CONFIG_HID_LENOVO_TPKBD) + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, +#endif { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, -- cgit v0.10.2 From e36851d0fa94b0f7802b3cc80406dbd3ef4f2f16 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Sep 2012 18:34:19 +0300 Subject: serial: omap: fix compile breakage when rebasing patches on top of Greg's tty-next, it looks like automerge broke a few things which I didn't catch (for whatever reason I didn't have OMAP Serial enabled on .config) so I ended up breaking the build on Greg's tty-next branch. Fix the breakage by re-adding the three missing members on struct uart_omap_port. Reported-by: Tony Lindgren Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h index 3c9fd3e..a531149 100644 --- a/arch/arm/plat-omap/include/plat/omap-serial.h +++ b/arch/arm/plat-omap/include/plat/omap-serial.h @@ -105,8 +105,4 @@ struct uart_omap_dma { unsigned int rx_timeout; }; - - int DTR_gpio; - int DTR_inverted; - int DTR_active; #endif /* __OMAP_SERIAL_H__ */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index cfd2094..0a6e78e 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -100,6 +100,10 @@ struct uart_omap_port { u8 wakeups_enabled; unsigned int irq_pending:1; + int DTR_gpio; + int DTR_inverted; + int DTR_active; + struct pm_qos_request pm_qos_request; u32 latency; u32 calc_latency; -- cgit v0.10.2 From b82b04e8eb27abe0cfe9cd7bf4fee8bb1bb9b013 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Wed, 29 Aug 2012 15:18:11 +0530 Subject: ARM: OMAP: omap_device: Do not overwrite resources allocated by OF layer With the new devices (like, AM33XX and OMAP5) we now only support DT boot mode of operation and now it is the time to start killing slowly the dependency on hwmod, so with this patch, we are starting with device resources. The idea here is implemented considering to both boot modes - - DT boot mode OF framework will construct the resource structure (currently does for MEM & IRQ resource) and we should respect/use these resources, killing hwmod dependency. If pdev->num_resources > 0, we assume that MEM & IRQ resources have been allocated by OF layer already (through DTB). Once DMA resource is available from OF layer, we should kill filling any resources from hwmod. - Non-DT boot mode Here, pdev->num_resources = 0, and we should get all the resources from hwmod (following existing steps) Signed-off-by: Vaibhav Hiremath Cc: Tony Lindgren Cc: Paul Walmsley Cc: Kevin Hilman [b-cousson@ti.com: Fix some checkpatch CHECK issues] Signed-off-by: Benoit Cousson diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 6ca8e51..7768804 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3158,6 +3158,33 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) } /** + * omap_hwmod_fill_dma_resources - fill struct resource array with dma data + * @oh: struct omap_hwmod * + * @res: pointer to the array of struct resource to fill + * + * Fill the struct resource array @res with dma resource data from the + * omap_hwmod @oh. Intended to be called by code that registers + * omap_devices. See also omap_hwmod_count_resources(). Returns the + * number of array elements filled. + */ +int omap_hwmod_fill_dma_resources(struct omap_hwmod *oh, struct resource *res) +{ + int i, sdma_reqs_cnt; + int r = 0; + + sdma_reqs_cnt = _count_sdma_reqs(oh); + for (i = 0; i < sdma_reqs_cnt; i++) { + (res + r)->name = (oh->sdma_reqs + i)->name; + (res + r)->start = (oh->sdma_reqs + i)->dma_req; + (res + r)->end = (oh->sdma_reqs + i)->dma_req; + (res + r)->flags = IORESOURCE_DMA; + r++; + } + + return r; +} + +/** * omap_hwmod_get_resource_byname - fetch IP block integration data by name * @oh: struct omap_hwmod * to operate on * @type: one of the IORESOURCE_* constants from include/linux/ioport.h diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 6132972..5857b9c 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -615,6 +615,7 @@ int omap_hwmod_softreset(struct omap_hwmod *oh); int omap_hwmod_count_resources(struct omap_hwmod *oh); int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res); +int omap_hwmod_fill_dma_resources(struct omap_hwmod *oh, struct resource *res); int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type, const char *name, struct resource *res); diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index ff57b5a..6f5c580 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -494,6 +494,33 @@ static int omap_device_fill_resources(struct omap_device *od, } /** + * _od_fill_dma_resources - fill in array of struct resource with dma resources + * @od: struct omap_device * + * @res: pointer to an array of struct resource to be filled in + * + * Populate one or more empty struct resource pointed to by @res with + * the dma resource data for this omap_device @od. Used by + * omap_device_alloc() after calling omap_device_count_resources(). + * + * Ideally this function would not be needed at all. If we have + * mechanism to get dma resources from DT. + * + * Returns 0. + */ +static int _od_fill_dma_resources(struct omap_device *od, + struct resource *res) +{ + int i, r; + + for (i = 0; i < od->hwmods_cnt; i++) { + r = omap_hwmod_fill_dma_resources(od->hwmods[i], res); + res += r; + } + + return 0; +} + +/** * omap_device_alloc - allocate an omap_device * @pdev: platform_device that will be included in this omap_device * @oh: ptr to the single omap_hwmod that backs this omap_device @@ -532,24 +559,44 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev, od->hwmods = hwmods; od->pdev = pdev; + res_count = omap_device_count_resources(od); /* - * HACK: Ideally the resources from DT should match, and hwmod - * should just add the missing ones. Since the name is not - * properly populated by DT, stick to hwmod resources only. + * DT Boot: + * OF framework will construct the resource structure (currently + * does for MEM & IRQ resource) and we should respect/use these + * resources, killing hwmod dependency. + * If pdev->num_resources > 0, we assume that MEM & IRQ resources + * have been allocated by OF layer already (through DTB). + * + * Non-DT Boot: + * Here, pdev->num_resources = 0, and we should get all the + * resources from hwmod. + * + * TODO: Once DMA resource is available from OF layer, we should + * kill filling any resources from hwmod. */ - if (pdev->num_resources && pdev->resource) - dev_warn(&pdev->dev, "%s(): resources already allocated %d\n", - __func__, pdev->num_resources); - - res_count = omap_device_count_resources(od); - if (res_count > 0) { - dev_dbg(&pdev->dev, "%s(): resources allocated from hwmod %d\n", - __func__, res_count); + if (res_count > pdev->num_resources) { + /* Allocate resources memory to account for new resources */ res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); if (!res) goto oda_exit3; - omap_device_fill_resources(od, res); + /* + * If pdev->num_resources > 0, then assume that, + * MEM and IRQ resources will only come from DT and only + * fill DMA resource from hwmod layer. + */ + if (pdev->num_resources && pdev->resource) { + dev_dbg(&pdev->dev, "%s(): resources already allocated %d\n", + __func__, res_count); + memcpy(res, pdev->resource, + sizeof(struct resource) * pdev->num_resources); + _od_fill_dma_resources(od, &res[pdev->num_resources]); + } else { + dev_dbg(&pdev->dev, "%s(): using resources from hwmod %d\n", + __func__, res_count); + omap_device_fill_resources(od, res); + } ret = platform_device_add_resources(pdev, res, res_count); kfree(res); -- cgit v0.10.2 From 6e6a9a504757e681e00d7212587950a925f66332 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 25 Jul 2012 10:57:58 +0530 Subject: ARM: dts: omap5-evm: Add I2C support Add I2C data nodes in omap5 device tree file. Signed-off-by: Sourav Poddar Acked-by: Santosh Shilimkar Acked-by: Felipe Balbi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 881d60c..424ad16 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -145,6 +145,41 @@ #interrupt-cells = <1>; }; + i2c1: i2c@48070000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c1"; + }; + + i2c2: i2c@48072000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c2"; + }; + + i2c3: i2c@48060000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c3"; + }; + + i2c4: i2c@4807A000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c4"; + }; + + i2c5: i2c@4807C000 { + compatible = "ti,omap4-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c5"; + }; + uart1: serial@4806a000 { compatible = "ti,omap4-uart"; ti,hwmods = "uart1"; -- cgit v0.10.2 From 08f3e21b81d4907e8ef513d97805d02df008f7d2 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 25 Jul 2012 11:02:43 +0530 Subject: ARM: dts: omap5-evm: Add tmp102 sensor support Add tmp102 temperature sensor data in omap5 evm dts file. Signed-off-by: Sourav Poddar Acked-by: Santosh Shilimkar Acked-by: Felipe Balbi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap5-evm.dts b/arch/arm/boot/dts/omap5-evm.dts index 7bb0c9d..1790f41 100644 --- a/arch/arm/boot/dts/omap5-evm.dts +++ b/arch/arm/boot/dts/omap5-evm.dts @@ -49,3 +49,13 @@ &mmc5 { status = "disabled"; }; + +&i2c4 { + clock-frequency = <400000>; + + /* Temperature Sensor */ + tmp102@48{ + compatible = "ti,tmp102"; + reg = <0x48>; + }; +}; -- cgit v0.10.2 From 5449fbc27b27317526391409b7bcacd2104a6a2f Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 25 Jul 2012 11:03:27 +0530 Subject: ARM: dts: omap5-evm: Add keypad data Add keypad data node in omap5 device tree file. Also fill the device tree binding parameters with the required value in "omap5-evm" dts file. Signed-off-by: Sourav Poddar Acked-by: Santosh Shilimkar Acked-by: Felipe Balbi [b-cousson@ti.com: Fix merge issue with MMC patches, put node at the proper place, align entries and comments] Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap5-evm.dts b/arch/arm/boot/dts/omap5-evm.dts index 1790f41..457d1ec 100644 --- a/arch/arm/boot/dts/omap5-evm.dts +++ b/arch/arm/boot/dts/omap5-evm.dts @@ -24,6 +24,7 @@ regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; }; + }; &mmc1 { @@ -59,3 +60,15 @@ reg = <0x48>; }; }; + +&keypad { + keypad,num-rows = <8>; + keypad,num-columns = <8>; + linux,keymap = <0x02020073 /* VOLUP */ + 0x02030072 /* VOLDOWM */ + 0x020400e7 /* SEND */ + 0x02050066 /* HOME */ + 0x0206006b /* END */ + 0x020700d9>; /* SEARCH */ + linux,input-no-autorepeat; +}; diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 424ad16..4c11ae1 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -246,5 +246,10 @@ ti,hwmods = "mmc5"; ti,needs-special-reset; }; + + keypad: keypad@4ae1c000 { + compatible = "ti,omap4-keypad"; + ti,hwmods = "kbd"; + }; }; }; -- cgit v0.10.2 From 288710151333ee2c730e9c9c26376c1dac83c292 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 25 Jul 2012 10:59:40 +0530 Subject: ARM: dts: omap5-evm: Add bmp085 sensor support Add bmp085 pressure sensor data in omap5 evm dts file. Signed-off-by: Sourav Poddar Acked-by: Santosh Shilimkar Acked-by: Felipe Balbi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap5-evm.dts b/arch/arm/boot/dts/omap5-evm.dts index 457d1ec..9c41a3f 100644 --- a/arch/arm/boot/dts/omap5-evm.dts +++ b/arch/arm/boot/dts/omap5-evm.dts @@ -51,6 +51,16 @@ status = "disabled"; }; +&i2c2 { + clock-frequency = <400000>; + + /* Pressure Sensor */ + bmp085@77 { + compatible = "bosch,bmp085"; + reg = <0x77>; + }; +}; + &i2c4 { clock-frequency = <400000>; -- cgit v0.10.2 From 61bc35445baacab98f500b3367d40e9b8cf41c43 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Tue, 14 Aug 2012 16:45:37 +0530 Subject: ARM: dts: omap4-sdp: Add keypad data Add keypad data node in omap4 device tree file. Also fill the device tree binding parameters with the required value in "omap4-sdp" dts file. Signed-off-by: Sourav Poddar Cc: Tony Lindgren Cc: Rob Herring Cc: Grant Likely Cc: Felipe Balbi Signed-off-by: Benoit Cousson [b-cousson@ti.com: Re-align the entries and the comments] diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index dbcdc4a..8869c1e 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -226,3 +226,73 @@ bus-width = <4>; ti,non-removable; }; + +&keypad { + keypad,num-rows = <8>; + keypad,num-columns = <8>; + linux,keymap = <0x00000012 /* KEY_E */ + 0x00010013 /* KEY_R */ + 0x00020014 /* KEY_T */ + 0x00030066 /* KEY_HOME */ + 0x0004003f /* KEY_F5 */ + 0x000500f0 /* KEY_UNKNOWN */ + 0x00060017 /* KEY_I */ + 0x0007002a /* KEY_LEFTSHIFT */ + 0x01000020 /* KEY_D*/ + 0x01010021 /* KEY_F */ + 0x01020022 /* KEY_G */ + 0x010300e7 /* KEY_SEND */ + 0x01040040 /* KEY_F6 */ + 0x010500f0 /* KEY_UNKNOWN */ + 0x01060025 /* KEY_K */ + 0x0107001c /* KEY_ENTER */ + 0x0200002d /* KEY_X */ + 0x0201002e /* KEY_C */ + 0x0202002f /* KEY_V */ + 0x0203006b /* KEY_END */ + 0x02040041 /* KEY_F7 */ + 0x020500f0 /* KEY_UNKNOWN */ + 0x02060034 /* KEY_DOT */ + 0x0207003a /* KEY_CAPSLOCK */ + 0x0300002c /* KEY_Z */ + 0x0301004e /* KEY_KPLUS */ + 0x03020030 /* KEY_B */ + 0x0303003b /* KEY_F1 */ + 0x03040042 /* KEY_F8 */ + 0x030500f0 /* KEY_UNKNOWN */ + 0x03060018 /* KEY_O */ + 0x03070039 /* KEY_SPACE */ + 0x04000011 /* KEY_W */ + 0x04010015 /* KEY_Y */ + 0x04020016 /* KEY_U */ + 0x0403003c /* KEY_F2 */ + 0x04040073 /* KEY_VOLUMEUP */ + 0x040500f0 /* KEY_UNKNOWN */ + 0x04060026 /* KEY_L */ + 0x04070069 /* KEY_LEFT */ + 0x0500001f /* KEY_S */ + 0x05010023 /* KEY_H */ + 0x05020024 /* KEY_J */ + 0x0503003d /* KEY_F3 */ + 0x05040043 /* KEY_F9 */ + 0x05050072 /* KEY_VOLUMEDOWN */ + 0x05060032 /* KEY_M */ + 0x0507006a /* KEY_RIGHT */ + 0x06000010 /* KEY_Q */ + 0x0601001e /* KEY_A */ + 0x06020031 /* KEY_N */ + 0x0603009e /* KEY_BACK */ + 0x0604000e /* KEY_BACKSPACE */ + 0x060500f0 /* KEY_UNKNOWN */ + 0x06060019 /* KEY_P */ + 0x06070067 /* KEY_UP */ + 0x07000094 /* KEY_PROG1 */ + 0x07010095 /* KEY_PROG2 */ + 0x070200ca /* KEY_PROG3 */ + 0x070300cb /* KEY_PROG4 */ + 0x0704003e /* KEY_F4 */ + 0x070500f0 /* KEY_UNKNOWN */ + 0x07060160 /* KEY_OK */ + 0x0707006c>; /* KEY_DOWN */ + linux,input-no-autorepeat; +}; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 04cbbcb..7fc45bb 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -295,5 +295,10 @@ interrupt-parent = <&gic>; ti,hwmods = "dmic"; }; + + keypad: keypad@4a31c000 { + compatible = "ti,omap4-keypad"; + ti,hwmods = "kbd"; + }; }; }; -- cgit v0.10.2 From 399264b897bc0efb4fb5c026705805bec9ed93b8 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 25 Jul 2012 10:57:58 +0530 Subject: Documentation: dt: i2c: trivial-devices: Update for tmp102 Add Description for tmp102 temperature sensor. Cc: Felipe Balbi Cc: Santosh Shilimkar Signed-off-by: Sourav Poddar Signed-off-by: Benoit Cousson diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 1a85f98..2f5322b 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -56,3 +56,4 @@ stm,m41t00 Serial Access TIMEKEEPER stm,m41t62 Serial real-time clock (RTC) with alarm stm,m41t80 M41T80 - SERIAL ACCESS RTC WITH ALARMS ti,tsc2003 I2C Touch-Screen Controller +ti,tmp102 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface -- cgit v0.10.2 From 274c27b1f18060db6cc6bedad7812e5a7f97c6a4 Mon Sep 17 00:00:00 2001 From: Aneesh V Date: Thu, 1 Dec 2011 17:47:09 +0530 Subject: Documentation: dt: device tree bindings for LPDDR2 memories device tree bindings for LPDDR2 SDRAM memories compliant to JESD209-2 standard. The 'lpddr2' binding in-turn uses another binding 'lpddr2-timings' for specifying the AC timing parameters of the memory device at different speed-bins. Reviewed-by: Benoit Cousson Reviewed-by: Grant Likely Tested-by: Lokesh Vutla Signed-off-by: Aneesh V [santosh.shilimkar@ti.com: Rebased against 3.6-rc] Signed-off-by: Santosh Shilimkar Signed-off-by: Benoit Cousson diff --git a/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt b/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt new file mode 100644 index 0000000..9ceb19e --- /dev/null +++ b/Documentation/devicetree/bindings/lpddr2/lpddr2-timings.txt @@ -0,0 +1,52 @@ +* AC timing parameters of LPDDR2(JESD209-2) memories for a given speed-bin + +Required properties: +- compatible : Should be "jedec,lpddr2-timings" +- min-freq : minimum DDR clock frequency for the speed-bin. Type is +- max-freq : maximum DDR clock frequency for the speed-bin. Type is + +Optional properties: + +The following properties represent AC timing parameters from the memory +data-sheet of the device for a given speed-bin. All these properties are +of type and the default unit is ps (pico seconds). Parameters with +a different unit have a suffix indicating the unit such as 'tRAS-max-ns' +- tRCD +- tWR +- tRAS-min +- tRRD +- tWTR +- tXP +- tRTP +- tDQSCK-max +- tFAW +- tZQCS +- tZQinit +- tRPab +- tZQCL +- tCKESR +- tRAS-max-ns +- tDQSCK-max-derated + +Example: + +timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; +}; diff --git a/Documentation/devicetree/bindings/lpddr2/lpddr2.txt b/Documentation/devicetree/bindings/lpddr2/lpddr2.txt new file mode 100644 index 0000000..58354a0 --- /dev/null +++ b/Documentation/devicetree/bindings/lpddr2/lpddr2.txt @@ -0,0 +1,102 @@ +* LPDDR2 SDRAM memories compliant to JEDEC JESD209-2 + +Required properties: +- compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2", + "jedec,lpddr2-s4" + + "ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type + + "ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type + + "ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type + +- density : representing density in Mb (Mega bits) + +- io-width : representing bus width. Possible values are 8, 16, and 32 + +Optional properties: + +The following optional properties represent the minimum value of some AC +timing parameters of the DDR device in terms of number of clock cycles. +These values shall be obtained from the device data-sheet. +- tRRD-min-tck +- tWTR-min-tck +- tXP-min-tck +- tRTP-min-tck +- tCKE-min-tck +- tRPab-min-tck +- tRCD-min-tck +- tWR-min-tck +- tRASmin-min-tck +- tCKESR-min-tck +- tFAW-min-tck + +Child nodes: +- The lpddr2 node may have one or more child nodes of type "lpddr2-timings". + "lpddr2-timings" provides AC timing parameters of the device for + a given speed-bin. The user may provide the timings for as many + speed-bins as is required. Please see Documentation/devicetree/ + bindings/lpddr2/lpddr2-timings.txt for more information on "lpddr2-timings" + +Example: + +elpida_ECB240ABACN : lpddr2 { + compatible = "Elpida,ECB240ABACN","jedec,lpddr2-s4"; + density = <2048>; + io-width = <32>; + + tRPab-min-tck = <3>; + tRCD-min-tck = <3>; + tWR-min-tck = <3>; + tRASmin-min-tck = <3>; + tRRD-min-tck = <2>; + tWTR-min-tck = <2>; + tXP-min-tck = <2>; + tRTP-min-tck = <2>; + tCKE-min-tck = <3>; + tCKESR-min-tck = <3>; + tFAW-min-tck = <8>; + + timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + + timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <200000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <10000>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + +} -- cgit v0.10.2 From 6bc9c66e5657a33d19559fce730bfa36112cb1cc Mon Sep 17 00:00:00 2001 From: Aneesh V Date: Sat, 17 Dec 2011 17:24:25 +0530 Subject: Documentation: dt: emif: device tree bindings for TI's EMIF sdram controller EMIF - External Memory Interface - is an SDRAM controller used in TI SoCs. EMIF supports, based on the IP revision, one or more of DDR2/DDR3/LPDDR2 protocols. This binding describes a given instance of the EMIF IP and memory parts attached to it. Reviewed-by: Grant Likely Tested-by: Lokesh Vutla Signed-off-by: Aneesh V [santosh.shilimkar@ti.com: Rebased against 3.6-rc] Signed-off-by: Santosh Shilimkar Signed-off-by: Benoit Cousson diff --git a/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt new file mode 100644 index 0000000..938f8e1 --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/ti/emif.txt @@ -0,0 +1,55 @@ +* EMIF family of TI SDRAM controllers + +EMIF - External Memory Interface - is an SDRAM controller used in +TI SoCs. EMIF supports, based on the IP revision, one or more of +DDR2/DDR3/LPDDR2 protocols. This binding describes a given instance +of the EMIF IP and memory parts attached to it. + +Required properties: +- compatible : Should be of the form "ti,emif-" where + is the IP revision of the specific EMIF instance. + +- phy-type : indicating the DDR phy type. Following are the + allowed values + <1> : Attila PHY + <2> : Intelli PHY + +- device-handle : phandle to a "lpddr2" node representing the memory part + +- ti,hwmods : For TI hwmods processing and omap device creation + the value shall be "emif" where is the number of the EMIF + instance with base 1. + +Optional properties: +- cs1-used : Have this property if CS1 of this EMIF + instance has a memory part attached to it. If there is a memory + part attached to CS1, it should be the same type as the one on CS0, + so there is no need to give the details of this memory part. + +- cal-resistor-per-cs : Have this property if the board has one + calibration resistor per chip-select. + +- hw-caps-read-idle-ctrl: Have this property if the controller + supports read idle window programming + +- hw-caps-dll-calib-ctrl: Have this property if the controller + supports dll calibration control + +- hw-caps-ll-interface : Have this property if the controller + has a low latency interface and corresponding interrupt events + +- hw-caps-temp-alert : Have this property if the controller + has capability for generating SDRAM temperature alerts + +Example: + +emif1: emif@0x4c000000 { + compatible = "ti,emif-4d"; + ti,hwmods = "emif2"; + phy-type = <1>; + device-handle = <&elpida_ECB240ABACN>; + cs1-used; + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; +}; -- cgit v0.10.2 From 11c27069cf963f7445a7b515bcb703d90ae0c162 Mon Sep 17 00:00:00 2001 From: Aneesh V Date: Fri, 20 Jan 2012 20:35:26 +0530 Subject: ARM: dts: EMIF and LPDDR2 device tree data for OMAP4 boards Device tree data for the EMIF sdram controllers in OMAP4 and LPDDR2 memory devices attached to OMAP4 boards. Reviewed-by: Grant Likely Tested-by: Lokesh Vutla Signed-off-by: Aneesh V [santosh.shilimkar@ti.com: Rebased against 3.6-rc] Signed-off-by: Santosh Shilimkar [b-cousson@ti.com: Use label in board to access EMIF nodes] Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/elpida_ecb240abacn.dtsi b/arch/arm/boot/dts/elpida_ecb240abacn.dtsi new file mode 100644 index 0000000..f97f70f --- /dev/null +++ b/arch/arm/boot/dts/elpida_ecb240abacn.dtsi @@ -0,0 +1,67 @@ +/* + * Common devices used in different OMAP boards + */ + +/ { + elpida_ECB240ABACN: lpddr2 { + compatible = "Elpida,ECB240ABACN","jedec,lpddr2-s4"; + density = <2048>; + io-width = <32>; + + tRPab-min-tck = <3>; + tRCD-min-tck = <3>; + tWR-min-tck = <3>; + tRASmin-min-tck = <3>; + tRRD-min-tck = <2>; + tWTR-min-tck = <2>; + tXP-min-tck = <2>; + tRTP-min-tck = <2>; + tCKE-min-tck = <3>; + tCKESR-min-tck = <3>; + tFAW-min-tck = <8>; + + timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + tDQSCK-max-derated = <6000>; + }; + + timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <200000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <10000>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + tDQSCK-max-derated = <6000>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts index 9880c12..20b966e 100644 --- a/arch/arm/boot/dts/omap4-panda.dts +++ b/arch/arm/boot/dts/omap4-panda.dts @@ -8,6 +8,7 @@ /dts-v1/; /include/ "omap4.dtsi" +/include/ "elpida_ecb240abacn.dtsi" / { model = "TI OMAP4 PandaBoard"; @@ -126,3 +127,13 @@ ti,non-removable; bus-width = <4>; }; + +&emif1 { + cs1-used; + device-handle = <&elpida_ECB240ABACN>; +}; + +&emif2 { + cs1-used; + device-handle = <&elpida_ECB240ABACN>; +}; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 8869c1e..7e83a61 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -8,6 +8,7 @@ /dts-v1/; /include/ "omap4.dtsi" +/include/ "elpida_ecb240abacn.dtsi" / { model = "TI OMAP4 SDP board"; @@ -227,6 +228,16 @@ ti,non-removable; }; +&emif1 { + cs1-used; + device-handle = <&elpida_ECB240ABACN>; +}; + +&emif2 { + cs1-used; + device-handle = <&elpida_ECB240ABACN>; +}; + &keypad { keypad,num-rows = <8>; keypad,num-columns = <8>; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 7fc45bb..c7dc11f 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -300,5 +300,23 @@ compatible = "ti,omap4-keypad"; ti,hwmods = "kbd"; }; + + emif1: emif@4c000000 { + compatible = "ti,emif-4d"; + ti,hwmods = "emif1"; + phy-type = <1>; + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; + }; + + emif2: emif@4d000000 { + compatible = "ti,emif-4d"; + ti,hwmods = "emif2"; + phy-type = <1>; + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; + }; }; }; -- cgit v0.10.2 From 926fd45ba9eeb4c3d0454b934161ee884dd82a22 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 4 Jul 2012 17:57:34 +0530 Subject: ARM: OMAP4: Add L2 Cache Controller in Device Tree Provide PL310 Level 2 Cache Controller Device Tree support for OMAP4 based devices. Signed-off-by: Santosh Shilimkar Acked-by: Felipe Balbi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index c7dc11f..cb18d2a 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -30,12 +30,21 @@ cpus { cpu@0 { compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; }; cpu@1 { compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; }; }; + L2: l2-cache-controller@48242000 { + compatible = "arm,pl310-cache"; + reg = <0x48242000 0x1000>; + cache-unified; + cache-level = <2>; + }; + /* * The soc node represents the soc top level view. It is uses for IPs * that are not memory mapped in the MPU view or for the MPU itself. diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index c29dee9..6f95992 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -171,7 +172,10 @@ static int __init omap_l2_cache_init(void) /* Enable PL310 L2 Cache controller */ omap_smc1(0x102, 0x1); - l2x0_init(l2cache_base, aux_ctrl, L2X0_AUX_CTRL_MASK); + if (of_have_populated_dt()) + l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK); + else + l2x0_init(l2cache_base, aux_ctrl, L2X0_AUX_CTRL_MASK); /* * Override default outer_cache.disable with a OMAP4 -- cgit v0.10.2 From eed0de27726a55f145490619510c8ec58c9dc767 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 4 Jul 2012 18:32:32 +0530 Subject: ARM: OMAP4: Add local timer support for Device Tree Add cortex-a9 local timer support for all OMAP4 based SOCs using DT. Signed-off-by: Santosh Shilimkar Acked-by: Felipe Balbi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index cb18d2a..2b670ab 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -45,6 +45,12 @@ cache-level = <2>; }; + local-timer@0x48240600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0x48240600 0x20>; + interrupts = <1 13 0x304>; + }; + /* * The soc node represents the soc top level view. It is uses for IPs * that are not memory mapped in the MPU view or for the MPU itself. diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 2ff6d41..31f9c93 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -386,6 +387,11 @@ static void __init omap4_timer_init(void) if (omap_rev() != OMAP4430_REV_ES1_0) { int err; + if (of_have_populated_dt()) { + twd_local_timer_of_register(); + return; + } + err = twd_local_timer_register(&twd_local_timer); if (err) pr_err("twd_local_timer_register failed %d\n", err); -- cgit v0.10.2 From 5635121edb18cda14a60e4702f3ae53add5df894 Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Mon, 3 Sep 2012 17:56:32 +0200 Subject: ARM: dts: OMAP4: Cleanup and move GIC outside of the OCP Remove some useless comment and move GIC controller outside of the OCP node since it does use the MPU internal bus and not the OCP. This will not change the functionality but will reflect the reality more accurately. Signed-off-by: Benoit Cousson Acked-by: Santosh Shilimkar diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 2b670ab..1853dc7 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -38,6 +38,14 @@ }; }; + gic: interrupt-controller@48241000 { + compatible = "arm,cortex-a9-gic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x48241000 0x1000>, + <0x48240100 0x0100>; + }; + L2: l2-cache-controller@48242000 { compatible = "arm,pl310-cache"; reg = <0x48242000 0x1000>; @@ -76,30 +84,6 @@ /* * XXX: Use a flat representation of the OMAP4 interconnect. * The real OMAP interconnect network is quite complex. - * - * MPU -+-- MPU_PRIVATE - GIC, L2 - * | - * +----------------+----------+ - * | | | - * + +- EMIF - DDR | - * | | | - * | + +--------+ - * | | | - * | +- L4_ABE - AESS, MCBSP, TIMERs... - * | | - * +- L3_MAIN --+- L4_CORE - IPs... - * | - * +- L4_PER - IPs... - * | - * +- L4_CFG -+- L4_WKUP - IPs... - * | | - * | +- IPs... - * +- IPU ----+ - * | | - * +- DSP ----+ - * | | - * +- DSS ----+ - * * Since that will not bring real advantage to represent that in DT for * the moment, just use a fake OCP bus entry to represent the whole bus * hierarchy. @@ -111,14 +95,6 @@ ranges; ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3"; - gic: interrupt-controller@48241000 { - compatible = "arm,cortex-a9-gic"; - interrupt-controller; - #interrupt-cells = <3>; - reg = <0x48241000 0x1000>, - <0x48240100 0x0100>; - }; - gpio1: gpio@4a310000 { compatible = "ti,omap4-gpio"; ti,hwmods = "gpio1"; -- cgit v0.10.2 From f74ce8fb849e9f9c54a494cff5fc30d53ca4e963 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Sep 2012 09:46:25 +0200 Subject: gpio/twl4030: get platform data from device tree Adds a number of missing device tree properties for twl4030/gpio, and update bindings: - "ti,use-leds" -> .use_leds - "ti,debounce" -> .debounce - "ti,mmc-cd" -> .mmc_cd - "ti,pullups" -> .pullups - "ti,pulldowns" -> .pulldowns Signed-off-by: Florian Vaussard Acked-by: Linus Walleij Acked-by: Vaibhav Hiremath [b-cousson@ti.com: Fix some checkpatch CHECK issues] Signed-off-by: Benoit Cousson diff --git a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt index 16695d9..66788fd 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-twl4030.txt @@ -11,6 +11,11 @@ Required properties: - interrupt-controller: Mark the device node as an interrupt controller The first cell is the GPIO number. The second cell is not used. +- ti,use-leds : Enables LEDA and LEDB outputs if set +- ti,debounce : if n-th bit is set, debounces GPIO-n +- ti,mmc-cd : if n-th bit is set, GPIO-n controls VMMC(n+1) +- ti,pullups : if n-th bit is set, set a pullup on GPIO-n +- ti,pulldowns : if n-th bit is set, set a pulldown on GPIO-n Example: @@ -20,4 +25,5 @@ twl_gpio: gpio { gpio-controller; #interrupt-cells = <2>; interrupt-controller; + ti,use-leds; }; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 94256fe..f923252 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -395,6 +395,31 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) static int gpio_twl4030_remove(struct platform_device *pdev); +static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) +{ + struct twl4030_gpio_platform_data *omap_twl_info; + + omap_twl_info = devm_kzalloc(dev, sizeof(*omap_twl_info), GFP_KERNEL); + if (!omap_twl_info) + return NULL; + + omap_twl_info->gpio_base = -1; + + omap_twl_info->use_leds = of_property_read_bool(dev->of_node, + "ti,use-leds"); + + of_property_read_u32(dev->of_node, "ti,debounce", + &omap_twl_info->debounce); + of_property_read_u32(dev->of_node, "ti,mmc-cd", + (u32 *)&omap_twl_info->mmc_cd); + of_property_read_u32(dev->of_node, "ti,pullups", + &omap_twl_info->pullups); + of_property_read_u32(dev->of_node, "ti,pulldowns", + &omap_twl_info->pulldowns); + + return omap_twl_info; +} + static int __devinit gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; @@ -423,39 +448,42 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev) twl4030_gpio_irq_base = irq_base; no_irqs: - twl_gpiochip.base = -1; twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; - if (pdata) { - twl_gpiochip.base = pdata->gpio_base; + if (node) + pdata = of_gpio_twl4030(&pdev->dev); - /* - * NOTE: boards may waste power if they don't set pullups - * and pulldowns correctly ... default for non-ULPI pins is - * pulldown, and some other pins may have external pullups - * or pulldowns. Careful! - */ - ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); - if (ret) - dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", - pdata->pullups, pdata->pulldowns, - ret); - - ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); - if (ret) - dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", - pdata->debounce, pdata->mmc_cd, - ret); - - /* - * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, - * is (still) clear if use_leds is set. - */ - if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform data is missing\n"); + return -ENXIO; } + twl_gpiochip.base = pdata->gpio_base; + + /* + * NOTE: boards may waste power if they don't set pullups + * and pulldowns correctly ... default for non-ULPI pins is + * pulldown, and some other pins may have external pullups + * or pulldowns. Careful! + */ + ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); + if (ret) + dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", + pdata->pullups, pdata->pulldowns, ret); + + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, ret); + + /* + * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, + * is (still) clear if use_leds is set. + */ + if (pdata->use_leds) + twl_gpiochip.ngpio += 2; + ret = gpiochip_add(&twl_gpiochip); if (ret < 0) { dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); -- cgit v0.10.2 From a60be2fe9735894b8e0e2de80d2bdb37d87cd0c5 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Wed, 5 Sep 2012 09:46:26 +0200 Subject: ARM: dts: omap3: Add gpio-twl4030 properties for BeagleBoard and omap3-EVM Add device tree properties for twl4030/gpio, according to the platform data of corresponding boards. This enables the led connected to LEDB output for both boards, as well as pullups/pulldowns on GPIO for the BeagleBoard. Signed-off-by: Florian Vaussard Acked-by: Linus Walleij Acked-by: Vaibhav Hiremath diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index e60cba0..3fe35c2 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -17,6 +17,14 @@ device_type = "memory"; reg = <0x80000000 0x20000000>; /* 512 MB */ }; + + leds { + compatible = "gpio-leds"; + pmu_stat { + label = "beagleboard::pmu_stat"; + gpios = <&twl_gpio 19 0>; /* LEDB */ + }; + }; }; &i2c1 { @@ -67,3 +75,15 @@ &mmc3 { status = "disabled"; }; + +&twl_gpio { + ti,use-leds; + /* pullups: BIT(1) */ + ti,pullups = <0x000002>; + /* + * pulldowns: + * BIT(2), BIT(6), BIT(7), BIT(8), BIT(13) + * BIT(15), BIT(16), BIT(17) + */ + ti,pulldowns = <0x03a1c4>; +}; diff --git a/arch/arm/boot/dts/omap3-evm.dts b/arch/arm/boot/dts/omap3-evm.dts index f349ee9..e8ba1c2 100644 --- a/arch/arm/boot/dts/omap3-evm.dts +++ b/arch/arm/boot/dts/omap3-evm.dts @@ -17,6 +17,15 @@ device_type = "memory"; reg = <0x80000000 0x10000000>; /* 256 MB */ }; + + leds { + compatible = "gpio-leds"; + ledb { + label = "omap3evm::ledb"; + gpios = <&twl_gpio 19 0>; /* LEDB */ + linux,default-trigger = "default-on"; + }; + }; }; &i2c1 { @@ -46,3 +55,7 @@ reg = <0x5c>; }; }; + +&twl_gpio { + ti,use-leds; +}; -- cgit v0.10.2 From 1c1737e5635d902e125394d7f66bccaf0f8c772c Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 5 Sep 2012 16:42:04 +0200 Subject: ARM: dts: omap3-beagle: Add heartbeat and mmc LEDs support Add the support for D6 and D7 LEDs on Beagle board. - D6 will be used for heartbeat - D7 will be used for mmc0 Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index 3fe35c2..ca46fb2 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -24,6 +24,18 @@ label = "beagleboard::pmu_stat"; gpios = <&twl_gpio 19 0>; /* LEDB */ }; + + heartbeat { + label = "beagleboard::usr0"; + gpios = <&gpio5 22 0>; /* 150 -> D6 LED */ + linux,default-trigger = "heartbeat"; + }; + + mmc { + label = "beagleboard::usr1"; + gpios = <&gpio5 21 0>; /* 149 -> D7 LED */ + linux,default-trigger = "mmc0"; + }; }; }; -- cgit v0.10.2 From 3f187f82948c236cfbc7df3783df50eedcf62d03 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 26 Jul 2012 17:01:32 +0300 Subject: ARM: dts: omap2: Add McBSP entries for OMAP2420 and OMAP2430 SoC The McBSP IP within OMAP2420 and 2430 is different we need to create separate dtsi files for them. Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi new file mode 100644 index 0000000..6174d3d --- /dev/null +++ b/arch/arm/boot/dts/omap2420.dtsi @@ -0,0 +1,39 @@ +/* + * Device Tree Source for OMAP2420 SoC + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "omap2.dtsi" + +/ { + compatible = "ti,omap2420", "ti,omap2"; + + ocp { + mcbsp1: mcbsp@48074000 { + compatible = "ti,omap2420-mcbsp"; + reg = <0x48074000 0xff>; + reg-names = "mpu"; + interrupts = <59>, /* TX interrupt */ + <60>; /* RX interrupt */ + interrupt-names = "tx", "rx"; + interrupt-parent = <&intc>; + ti,hwmods = "mcbsp1"; + }; + + mcbsp2: mcbsp@48076000 { + compatible = "ti,omap2420-mcbsp"; + reg = <0x48076000 0xff>; + reg-names = "mpu"; + interrupts = <62>, /* TX interrupt */ + <63>; /* RX interrupt */ + interrupt-names = "tx", "rx"; + interrupt-parent = <&intc>; + ti,hwmods = "mcbsp2"; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi new file mode 100644 index 0000000..59a639a --- /dev/null +++ b/arch/arm/boot/dts/omap2430.dtsi @@ -0,0 +1,83 @@ +/* + * Device Tree Source for OMAP243x SoC + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "omap2.dtsi" + +/ { + compatible = "ti,omap2430", "ti,omap2"; + + ocp { + mcbsp1: mcbsp@48074000 { + compatible = "ti,omap2430-mcbsp"; + reg = <0x48074000 0xff>; + reg-names = "mpu"; + interrupts = <64>, /* OCP compliant interrupt */ + <59>, /* TX interrupt */ + <60>, /* RX interrupt */ + <61>; /* RX overflow interrupt */ + interrupt-names = "common", "tx", "rx", "rx_overflow"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp1"; + }; + + mcbsp2: mcbsp@48076000 { + compatible = "ti,omap2430-mcbsp"; + reg = <0x48076000 0xff>; + reg-names = "mpu"; + interrupts = <16>, /* OCP compliant interrupt */ + <62>, /* TX interrupt */ + <63>; /* RX interrupt */ + interrupt-names = "common", "tx", "rx"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp2"; + }; + + mcbsp3: mcbsp@4808c000 { + compatible = "ti,omap2430-mcbsp"; + reg = <0x4808c000 0xff>; + reg-names = "mpu"; + interrupts = <17>, /* OCP compliant interrupt */ + <89>, /* TX interrupt */ + <90>; /* RX interrupt */ + interrupt-names = "common", "tx", "rx"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp3"; + }; + + mcbsp4: mcbsp@4808e000 { + compatible = "ti,omap2430-mcbsp"; + reg = <0x4808e000 0xff>; + reg-names = "mpu"; + interrupts = <18>, /* OCP compliant interrupt */ + <54>, /* TX interrupt */ + <55>; /* RX interrupt */ + interrupt-names = "common", "tx", "rx"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp4"; + }; + + mcbsp5: mcbsp@48096000 { + compatible = "ti,omap2430-mcbsp"; + reg = <0x48096000 0xff>; + reg-names = "mpu"; + interrupts = <19>, /* OCP compliant interrupt */ + <81>, /* TX interrupt */ + <82>; /* RX interrupt */ + interrupt-names = "common", "tx", "rx"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp5"; + }; + }; +}; -- cgit v0.10.2 From 40c9e5cacfc186b537b402a59319cd6a88ce338b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 8 Aug 2012 11:02:52 +0300 Subject: ARM: dts: omap2420-h4: Include omap2420.dtsi file instead the common omap2 Since the board is based on OMAP2420 we should include the dedicated dtsi file (which includes the common omap2 dtsi). Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap2420-h4.dts b/arch/arm/boot/dts/omap2420-h4.dts index 25b50b7..77b84e1 100644 --- a/arch/arm/boot/dts/omap2420-h4.dts +++ b/arch/arm/boot/dts/omap2420-h4.dts @@ -7,7 +7,7 @@ */ /dts-v1/; -/include/ "omap2.dtsi" +/include/ "omap2420.dtsi" / { model = "TI OMAP2420 H4 board"; -- cgit v0.10.2 From 0be484bf4d0e9a78520b9e576de03de89e9d5882 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 5 Sep 2012 14:21:22 +0300 Subject: ARM: dts: omap3: Add McBSP entries Create the needed sections to be able to probe McBSP ports via DT. Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index 8109471..f024bb3 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -220,5 +220,74 @@ compatible = "ti,omap3-wdt"; ti,hwmods = "wd_timer2"; }; + + mcbsp1: mcbsp@48074000 { + compatible = "ti,omap3-mcbsp"; + reg = <0x48074000 0xff>; + reg-names = "mpu"; + interrupts = <16>, /* OCP compliant interrupt */ + <59>, /* TX interrupt */ + <60>; /* RX interrupt */ + interrupt-names = "common", "tx", "rx"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp1"; + }; + + mcbsp2: mcbsp@49022000 { + compatible = "ti,omap3-mcbsp"; + reg = <0x49022000 0xff>, + <0x49028000 0xff>; + reg-names = "mpu", "sidetone"; + interrupts = <17>, /* OCP compliant interrupt */ + <62>, /* TX interrupt */ + <63>, /* RX interrupt */ + <4>; /* Sidetone */ + interrupt-names = "common", "tx", "rx", "sidetone"; + interrupt-parent = <&intc>; + ti,buffer-size = <1280>; + ti,hwmods = "mcbsp2"; + }; + + mcbsp3: mcbsp@49024000 { + compatible = "ti,omap3-mcbsp"; + reg = <0x49024000 0xff>, + <0x4902a000 0xff>; + reg-names = "mpu", "sidetone"; + interrupts = <22>, /* OCP compliant interrupt */ + <89>, /* TX interrupt */ + <90>, /* RX interrupt */ + <5>; /* Sidetone */ + interrupt-names = "common", "tx", "rx", "sidetone"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp3"; + }; + + mcbsp4: mcbsp@49026000 { + compatible = "ti,omap3-mcbsp"; + reg = <0x49026000 0xff>; + reg-names = "mpu"; + interrupts = <23>, /* OCP compliant interrupt */ + <54>, /* TX interrupt */ + <55>; /* RX interrupt */ + interrupt-names = "common", "tx", "rx"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp4"; + }; + + mcbsp5: mcbsp@48096000 { + compatible = "ti,omap3-mcbsp"; + reg = <0x48096000 0xff>; + reg-names = "mpu"; + interrupts = <27>, /* OCP compliant interrupt */ + <81>, /* TX interrupt */ + <82>; /* RX interrupt */ + interrupt-names = "common", "tx", "rx"; + interrupt-parent = <&intc>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp5"; + }; }; }; -- cgit v0.10.2 From 2995a10002e20b5acfbaf9553ca1f22d9575f032 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 26 Jul 2012 17:13:21 +0300 Subject: ARM: dts: omap4: Add McBSP entries Create the sections describing the McBSP ports to be able to use them via DT. Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 1853dc7..5ed3b94 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -287,6 +287,53 @@ ti,hwmods = "dmic"; }; + mcbsp1: mcbsp@40122000 { + compatible = "ti,omap4-mcbsp"; + reg = <0x40122000 0xff>, /* MPU private access */ + <0x49022000 0xff>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 17 0x4>; + interrupt-names = "common"; + interrupt-parent = <&gic>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp1"; + }; + + mcbsp2: mcbsp@40124000 { + compatible = "ti,omap4-mcbsp"; + reg = <0x40124000 0xff>, /* MPU private access */ + <0x49024000 0xff>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 22 0x4>; + interrupt-names = "common"; + interrupt-parent = <&gic>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp2"; + }; + + mcbsp3: mcbsp@40126000 { + compatible = "ti,omap4-mcbsp"; + reg = <0x40126000 0xff>, /* MPU private access */ + <0x49026000 0xff>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 23 0x4>; + interrupt-names = "common"; + interrupt-parent = <&gic>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp3"; + }; + + mcbsp4: mcbsp@48096000 { + compatible = "ti,omap4-mcbsp"; + reg = <0x48096000 0xff>; /* L4 Interconnect */ + reg-names = "mpu"; + interrupts = <0 16 0x4>; + interrupt-names = "common"; + interrupt-parent = <&gic>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp4"; + }; + keypad: keypad@4a31c000 { compatible = "ti,omap4-keypad"; ti,hwmods = "kbd"; -- cgit v0.10.2 From 63467cf23284588901f2edfcaabbfdef489ffc9b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Aug 2012 16:31:06 +0300 Subject: ARM: dts: omap4: Add reg-names for McPDM and DMIC In order to get the memory areas by name when booted with DT. Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 5ed3b94..9f851df 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -273,6 +273,7 @@ compatible = "ti,omap4-mcpdm"; reg = <0x40132000 0x7f>, /* MPU private access */ <0x49032000 0x7f>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; interrupts = <0 112 0x4>; interrupt-parent = <&gic>; ti,hwmods = "mcpdm"; @@ -282,6 +283,7 @@ compatible = "ti,omap4-dmic"; reg = <0x4012e000 0x7f>, /* MPU private access */ <0x4902e000 0x7f>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; interrupts = <0 114 0x4>; interrupt-parent = <&gic>; ti,hwmods = "dmic"; -- cgit v0.10.2 From ffd5db24e7491135da12d73244d6974153f4765f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Aug 2012 16:31:04 +0300 Subject: ARM: dts: omap5: Add McBSP entries Create the sections describing the McBSP ports to be able to use them via DT. Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index 4c11ae1..aa97e93 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -251,5 +251,41 @@ compatible = "ti,omap4-keypad"; ti,hwmods = "kbd"; }; + + mcbsp1: mcbsp@40122000 { + compatible = "ti,omap4-mcbsp"; + reg = <0x40122000 0xff>, /* MPU private access */ + <0x49022000 0xff>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 17 0x4>; + interrupt-names = "common"; + interrupt-parent = <&gic>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp1"; + }; + + mcbsp2: mcbsp@40124000 { + compatible = "ti,omap4-mcbsp"; + reg = <0x40124000 0xff>, /* MPU private access */ + <0x49024000 0xff>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 22 0x4>; + interrupt-names = "common"; + interrupt-parent = <&gic>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp2"; + }; + + mcbsp3: mcbsp@40126000 { + compatible = "ti,omap4-mcbsp"; + reg = <0x40126000 0xff>, /* MPU private access */ + <0x49026000 0xff>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 23 0x4>; + interrupt-names = "common"; + interrupt-parent = <&gic>; + ti,buffer-size = <128>; + ti,hwmods = "mcbsp3"; + }; }; }; -- cgit v0.10.2 From cbb57f071f4dbd7684e6b7280dbc2286fdcecf0b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Aug 2012 16:31:07 +0300 Subject: ARM: dts: omap5: Add McPDM and DMIC section to the dtsi file To be able to load the McPDM and DMIC driver when booted with device tree. Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi index aa97e93..9ac75b3 100644 --- a/arch/arm/boot/dts/omap5.dtsi +++ b/arch/arm/boot/dts/omap5.dtsi @@ -252,6 +252,26 @@ ti,hwmods = "kbd"; }; + mcpdm: mcpdm@40132000 { + compatible = "ti,omap4-mcpdm"; + reg = <0x40132000 0x7f>, /* MPU private access */ + <0x49032000 0x7f>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 112 0x4>; + interrupt-parent = <&gic>; + ti,hwmods = "mcpdm"; + }; + + dmic: dmic@4012e000 { + compatible = "ti,omap4-dmic"; + reg = <0x4012e000 0x7f>, /* MPU private access */ + <0x4902e000 0x7f>; /* L3 Interconnect */ + reg-names = "mpu", "dma"; + interrupts = <0 114 0x4>; + interrupt-parent = <&gic>; + ti,hwmods = "dmic"; + }; + mcbsp1: mcbsp@40122000 { compatible = "ti,omap4-mcbsp"; reg = <0x40122000 0xff>, /* MPU private access */ -- cgit v0.10.2 From 2c195f9cebeb03f7fb10ede6aeca5ce3ce6ed350 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 29 Aug 2012 16:31:05 +0300 Subject: ARM: dts: omap3-beagle: Enable audio support Add the needed sections to enable audio support on BeagleBoard when booted with DT blob. Signed-off-by: Peter Ujfalusi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index ca46fb2..a9d98d5 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -37,6 +37,14 @@ linux,default-trigger = "mmc0"; }; }; + + sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3beagle"; + + ti,mcbsp = <&mcbsp2>; + ti,codec = <&twl_audio>; + }; }; &i2c1 { @@ -52,6 +60,12 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3000000>; }; + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + codec { + }; + }; }; }; -- cgit v0.10.2 From 5d83cb86227baf87ab04a646d60fb8b26b880743 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 27 Aug 2012 16:59:08 +0530 Subject: ARM: dts: AM33XX: Convert all hex numbers to lower-case To make it consistent, convert all hex number presentation to lower-case from all am33xx specific nodes. Signed-off-by: Vaibhav Hiremath Cc: Tony Lindgren Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts index 917e784..c634f87 100644 --- a/arch/arm/boot/dts/am335x-bone.dts +++ b/arch/arm/boot/dts/am335x-bone.dts @@ -19,11 +19,11 @@ }; ocp { - uart1: serial@44E09000 { + uart1: serial@44e09000 { status = "okay"; }; - i2c1: i2c@44E0B000 { + i2c1: i2c@44e0b000 { status = "okay"; clock-frequency = <400000>; diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index 9fcbacd..185d632 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -19,16 +19,16 @@ }; ocp { - uart1: serial@44E09000 { + uart1: serial@44e09000 { status = "okay"; }; - i2c1: i2c@44E0B000 { + i2c1: i2c@44e0b000 { status = "okay"; clock-frequency = <400000>; - tps: tps@2D { - reg = <0x2D>; + tps: tps@2d { + reg = <0x2d>; }; }; }; diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index dde76f7..be43511 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -71,7 +71,7 @@ #interrupt-cells = <1>; }; - gpio2: gpio@4804C000 { + gpio2: gpio@4804c000 { compatible = "ti,omap4-gpio"; ti,hwmods = "gpio2"; gpio-controller; @@ -80,7 +80,7 @@ #interrupt-cells = <1>; }; - gpio3: gpio@481AC000 { + gpio3: gpio@481ac000 { compatible = "ti,omap4-gpio"; ti,hwmods = "gpio3"; gpio-controller; @@ -89,7 +89,7 @@ #interrupt-cells = <1>; }; - gpio4: gpio@481AE000 { + gpio4: gpio@481ae000 { compatible = "ti,omap4-gpio"; ti,hwmods = "gpio4"; gpio-controller; @@ -98,7 +98,7 @@ #interrupt-cells = <1>; }; - uart1: serial@44E09000 { + uart1: serial@44e09000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart1"; clock-frequency = <48000000>; @@ -119,28 +119,28 @@ status = "disabled"; }; - uart4: serial@481A6000 { + uart4: serial@481a6000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart4"; clock-frequency = <48000000>; status = "disabled"; }; - uart5: serial@481A8000 { + uart5: serial@481a8000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart5"; clock-frequency = <48000000>; status = "disabled"; }; - uart6: serial@481AA000 { + uart6: serial@481aa000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart6"; clock-frequency = <48000000>; status = "disabled"; }; - i2c1: i2c@44E0B000 { + i2c1: i2c@44e0b000 { compatible = "ti,omap4-i2c"; #address-cells = <1>; #size-cells = <0>; @@ -148,7 +148,7 @@ status = "disabled"; }; - i2c2: i2c@4802A000 { + i2c2: i2c@4802a000 { compatible = "ti,omap4-i2c"; #address-cells = <1>; #size-cells = <0>; @@ -156,7 +156,7 @@ status = "disabled"; }; - i2c3: i2c@4819C000 { + i2c3: i2c@4819c000 { compatible = "ti,omap4-i2c"; #address-cells = <1>; #size-cells = <0>; -- cgit v0.10.2 From 4462b31cf416e74e54a37b57de7177cc4d244699 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 27 Aug 2012 17:21:01 +0530 Subject: ARM: dts: AM33XX: Specify reg and interrupt property for all nodes The device/node resources (like, IORESOURCE_MEM and IORESOURCE_IRQ) are overwritten by hwmod resources, due to all known reasons but that should not be the reason for not providing all the information in the DTS blob. Ideally we should use DTS resource and use HWMOD framework wherever required and for only specific things. Newer platforms like, OMAP5 and AM33XX, we only support DT boot mode, so this patch is preparation for the future where we supposed to get rid of hwmod dependency anyway. Signed-off-by: Vaibhav Hiremath Cc: Tony Lindgren Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index be43511..bb31bff 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -69,6 +69,9 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <1>; + reg = <0x44e07000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <96>; }; gpio2: gpio@4804c000 { @@ -78,6 +81,9 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <1>; + reg = <0x4804c000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <98>; }; gpio3: gpio@481ac000 { @@ -87,6 +93,9 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <1>; + reg = <0x481ac000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <32>; }; gpio4: gpio@481ae000 { @@ -96,12 +105,18 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <1>; + reg = <0x481ae000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <62>; }; uart1: serial@44e09000 { compatible = "ti,omap3-uart"; ti,hwmods = "uart1"; clock-frequency = <48000000>; + reg = <0x44e09000 0x2000>; + interrupt-parent = <&intc>; + interrupts = <72>; status = "disabled"; }; @@ -109,6 +124,9 @@ compatible = "ti,omap3-uart"; ti,hwmods = "uart2"; clock-frequency = <48000000>; + reg = <0x48022000 0x2000>; + interrupt-parent = <&intc>; + interrupts = <73>; status = "disabled"; }; @@ -116,6 +134,9 @@ compatible = "ti,omap3-uart"; ti,hwmods = "uart3"; clock-frequency = <48000000>; + reg = <0x48024000 0x2000>; + interrupt-parent = <&intc>; + interrupts = <74>; status = "disabled"; }; @@ -123,6 +144,9 @@ compatible = "ti,omap3-uart"; ti,hwmods = "uart4"; clock-frequency = <48000000>; + reg = <0x481a6000 0x2000>; + interrupt-parent = <&intc>; + interrupts = <44>; status = "disabled"; }; @@ -130,6 +154,9 @@ compatible = "ti,omap3-uart"; ti,hwmods = "uart5"; clock-frequency = <48000000>; + reg = <0x481a8000 0x2000>; + interrupt-parent = <&intc>; + interrupts = <45>; status = "disabled"; }; @@ -137,6 +164,9 @@ compatible = "ti,omap3-uart"; ti,hwmods = "uart6"; clock-frequency = <48000000>; + reg = <0x481aa000 0x2000>; + interrupt-parent = <&intc>; + interrupts = <46>; status = "disabled"; }; @@ -145,6 +175,9 @@ #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c1"; + reg = <0x44e0b000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <70>; status = "disabled"; }; @@ -153,6 +186,9 @@ #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c2"; + reg = <0x4802a000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <71>; status = "disabled"; }; @@ -161,12 +197,18 @@ #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c3"; + reg = <0x4819c000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <30>; status = "disabled"; }; wdt2: wdt@44e35000 { compatible = "ti,omap3-wdt"; ti,hwmods = "wd_timer2"; + reg = <0x44e35000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <91>; }; }; }; -- cgit v0.10.2 From 48420dbcf2168004f8a5ed9f1ecd2d877dc798da Mon Sep 17 00:00:00 2001 From: Benoit Cousson Date: Wed, 5 Sep 2012 11:38:23 +0200 Subject: ARM: dts: OMAP4: Add reg and interrupts for every nodes Thanks to Vaibhav omap_device fix (ARM: OMAP: omap_device: Fix up resource names when booted with devicetre), we can now specify reg and interrupts using standard device tree attributes. Update the OMAP4 dtsi file with missing reg and interrupts attributes. Signed-off-by: Benoit Cousson Cc: Santosh Shilimkar Cc: Tony Lindgren Cc: Felipe Balbi Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 9f851df..75095e3 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -97,6 +97,8 @@ gpio1: gpio@4a310000 { compatible = "ti,omap4-gpio"; + reg = <0x4a310000 0x200>; + interrupts = <0 29 0x4>; ti,hwmods = "gpio1"; gpio-controller; #gpio-cells = <2>; @@ -106,6 +108,8 @@ gpio2: gpio@48055000 { compatible = "ti,omap4-gpio"; + reg = <0x48055000 0x200>; + interrupts = <0 30 0x4>; ti,hwmods = "gpio2"; gpio-controller; #gpio-cells = <2>; @@ -115,6 +119,8 @@ gpio3: gpio@48057000 { compatible = "ti,omap4-gpio"; + reg = <0x48057000 0x200>; + interrupts = <0 31 0x4>; ti,hwmods = "gpio3"; gpio-controller; #gpio-cells = <2>; @@ -124,6 +130,8 @@ gpio4: gpio@48059000 { compatible = "ti,omap4-gpio"; + reg = <0x48059000 0x200>; + interrupts = <0 32 0x4>; ti,hwmods = "gpio4"; gpio-controller; #gpio-cells = <2>; @@ -133,6 +141,8 @@ gpio5: gpio@4805b000 { compatible = "ti,omap4-gpio"; + reg = <0x4805b000 0x200>; + interrupts = <0 33 0x4>; ti,hwmods = "gpio5"; gpio-controller; #gpio-cells = <2>; @@ -142,6 +152,8 @@ gpio6: gpio@4805d000 { compatible = "ti,omap4-gpio"; + reg = <0x4805d000 0x200>; + interrupts = <0 34 0x4>; ti,hwmods = "gpio6"; gpio-controller; #gpio-cells = <2>; @@ -151,30 +163,40 @@ uart1: serial@4806a000 { compatible = "ti,omap4-uart"; + reg = <0x4806a000 0x100>; + interrupts = <0 72 0x4>; ti,hwmods = "uart1"; clock-frequency = <48000000>; }; uart2: serial@4806c000 { compatible = "ti,omap4-uart"; + reg = <0x4806c000 0x100>; + interrupts = <0 73 0x4>; ti,hwmods = "uart2"; clock-frequency = <48000000>; }; uart3: serial@48020000 { compatible = "ti,omap4-uart"; + reg = <0x48020000 0x100>; + interrupts = <0 74 0x4>; ti,hwmods = "uart3"; clock-frequency = <48000000>; }; uart4: serial@4806e000 { compatible = "ti,omap4-uart"; + reg = <0x4806e000 0x100>; + interrupts = <0 70 0x4>; ti,hwmods = "uart4"; clock-frequency = <48000000>; }; i2c1: i2c@48070000 { compatible = "ti,omap4-i2c"; + reg = <0x48070000 0x100>; + interrupts = <0 56 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c1"; @@ -182,6 +204,8 @@ i2c2: i2c@48072000 { compatible = "ti,omap4-i2c"; + reg = <0x48072000 0x100>; + interrupts = <0 57 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c2"; @@ -189,6 +213,8 @@ i2c3: i2c@48060000 { compatible = "ti,omap4-i2c"; + reg = <0x48060000 0x100>; + interrupts = <0 61 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c3"; @@ -196,6 +222,8 @@ i2c4: i2c@48350000 { compatible = "ti,omap4-i2c"; + reg = <0x48350000 0x100>; + interrupts = <0 62 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "i2c4"; @@ -203,6 +231,8 @@ mcspi1: spi@48098000 { compatible = "ti,omap4-mcspi"; + reg = <0x48098000 0x200>; + interrupts = <0 65 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi1"; @@ -211,6 +241,8 @@ mcspi2: spi@4809a000 { compatible = "ti,omap4-mcspi"; + reg = <0x4809a000 0x200>; + interrupts = <0 66 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi2"; @@ -219,6 +251,8 @@ mcspi3: spi@480b8000 { compatible = "ti,omap4-mcspi"; + reg = <0x480b8000 0x200>; + interrupts = <0 91 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi3"; @@ -227,6 +261,8 @@ mcspi4: spi@480ba000 { compatible = "ti,omap4-mcspi"; + reg = <0x480ba000 0x200>; + interrupts = <0 48 0x4>; #address-cells = <1>; #size-cells = <0>; ti,hwmods = "mcspi4"; @@ -235,6 +271,8 @@ mmc1: mmc@4809c000 { compatible = "ti,omap4-hsmmc"; + reg = <0x4809c000 0x400>; + interrupts = <0 83 0x4>; ti,hwmods = "mmc1"; ti,dual-volt; ti,needs-special-reset; @@ -242,30 +280,40 @@ mmc2: mmc@480b4000 { compatible = "ti,omap4-hsmmc"; + reg = <0x480b4000 0x400>; + interrupts = <0 86 0x4>; ti,hwmods = "mmc2"; ti,needs-special-reset; }; mmc3: mmc@480ad000 { compatible = "ti,omap4-hsmmc"; + reg = <0x480ad000 0x400>; + interrupts = <0 94 0x4>; ti,hwmods = "mmc3"; ti,needs-special-reset; }; mmc4: mmc@480d1000 { compatible = "ti,omap4-hsmmc"; + reg = <0x480d1000 0x400>; + interrupts = <0 96 0x4>; ti,hwmods = "mmc4"; ti,needs-special-reset; }; mmc5: mmc@480d5000 { compatible = "ti,omap4-hsmmc"; + reg = <0x480d5000 0x400>; + interrupts = <0 59 0x4>; ti,hwmods = "mmc5"; ti,needs-special-reset; }; wdt2: wdt@4a314000 { compatible = "ti,omap4-wdt", "ti,omap3-wdt"; + reg = <0x4a314000 0x80>; + interrupts = <0 80 0x4>; ti,hwmods = "wd_timer2"; }; @@ -338,11 +386,16 @@ keypad: keypad@4a31c000 { compatible = "ti,omap4-keypad"; + reg = <0x4a31c000 0x80>; + interrupts = <0 120 0x4>; + reg-names = "mpu"; ti,hwmods = "kbd"; }; emif1: emif@4c000000 { compatible = "ti,emif-4d"; + reg = <0x4c000000 0x100>; + interrupts = <0 110 0x4>; ti,hwmods = "emif1"; phy-type = <1>; hw-caps-read-idle-ctrl; @@ -352,6 +405,8 @@ emif2: emif@4d000000 { compatible = "ti,emif-4d"; + reg = <0x4d000000 0x100>; + interrupts = <0 111 0x4>; ti,hwmods = "emif2"; phy-type = <1>; hw-caps-read-idle-ctrl; -- cgit v0.10.2 From 55d512e245bc7699a8800e23df1a24195dd08217 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 8 Sep 2012 16:43:45 -0700 Subject: Linux 3.6-rc5 diff --git a/Makefile b/Makefile index 371ce88..0f66f14 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 6 SUBLEVEL = 0 -EXTRAVERSION = -rc4 +EXTRAVERSION = -rc5 NAME = Saber-toothed Squirrel # *DOCUMENTATION* -- cgit v0.10.2 From bc7fedad82deb398f440b875f54dc81f931a71e3 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Aug 2012 18:06:11 +0200 Subject: ARM: dts: OMAP3: Add support for Gumstix Overo with Tobi expansion board The Gumstix Overo is a computer on module using an OMAP3 processor. This module must be plugged into an expansion board. This patch adds a first device tree support for the Overo, using the Tobi expansion board. The current support is able to boot and mount the rootfs from MMC. This patche also updates the omap3 dtb build target. Currently working: - mmc0 (on board microSD) - i2c0 and i2c2 (i2c1 not used) - led on GPIO Signed-off-by: Florian Vaussard Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi new file mode 100644 index 0000000..d6cc5e2 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo.dtsi @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * The Gumstix Overo must be combined with an expansion board. + */ +/dts-v1/; + +/include/ "omap3.dtsi" + +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + }; +}; + +/include/ "twl4030.dtsi" + +/* i2c2 pins are used for gpio */ +&i2c2 { + status = "disabled"; +}; + +/* on board microSD slot */ +&mmc1 { + vmmc-supply = <&vmmc1>; + bus-width = <4>; +}; + +/* optional on board WiFi */ +&mmc2 { + bus-width = <4>; +}; diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-tobi.dts new file mode 100644 index 0000000..a13d12d --- /dev/null +++ b/arch/arm/boot/dts/omap3-tobi.dts @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Tobi expansion board is manufactured by Gumstix Inc. + */ + +/include/ "omap3-overo.dtsi" + +/ { + model = "TI OMAP3 Gumstix Overo on Tobi"; + compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"; + + leds { + compatible = "gpio-leds"; + heartbeat { + label = "overo:red:gpio21"; + gpios = <&gpio1 21 0>; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; +}; + +&mmc3 { + status = "disabled"; +}; diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot index 6cf1c2d..18813ab 100644 --- a/arch/arm/mach-omap2/Makefile.boot +++ b/arch/arm/mach-omap2/Makefile.boot @@ -3,7 +3,7 @@ params_phys-y := 0x80000100 initrd_phys-y := 0x80800000 dtb-$(CONFIG_SOC_OMAP2420) += omap2420-h4.dtb -dtb-$(CONFIG_ARCH_OMAP3) += omap3-beagle.dtb omap3-evm.dtb +dtb-$(CONFIG_ARCH_OMAP3) += omap3-beagle.dtb omap3-evm.dtb omap3-tobi.dtb dtb-$(CONFIG_ARCH_OMAP4) += omap4-panda.dtb omap4-pandaES.dtb dtb-$(CONFIG_ARCH_OMAP4) += omap4-var_som.dtb omap4-sdp.dtb dtb-$(CONFIG_SOC_OMAP5) += omap5-evm.dtb -- cgit v0.10.2 From 807e1b426db755a605f0aa03604c1cd00630e727 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Fri, 31 Aug 2012 18:06:12 +0200 Subject: Documentation: dt: Update the OMAP documentation with Overo/Toby Add the Tobi/Overo board to the list of supported platforms. Signed-off-by: Florian Vaussard Signed-off-by: Benoit Cousson diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index ccdd0e5..d0051a7 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -36,6 +36,9 @@ Boards: - OMAP3 BeagleBoard : Low cost community board compatible = "ti,omap3-beagle", "ti,omap3" +- OMAP3 Tobi with Overo : Commercial expansion board with daughter board + compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3" + - OMAP4 SDP : Software Developement Board compatible = "ti,omap4-sdp", "ti,omap4430" -- cgit v0.10.2 From a135f2f82c64fa779adbc19b41e21039a258a6a4 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Mon, 10 Sep 2012 15:16:36 +0200 Subject: ARM: dts: omap3-overo: Add support for the blue LED Support the blue LED connected to the LEDB pin of the TWL4030 on the Gumstix Overo. Signed-off-by: Florian Vaussard Signed-off-by: Benoit Cousson diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi index d6cc5e2..89808ce 100644 --- a/arch/arm/boot/dts/omap3-overo.dtsi +++ b/arch/arm/boot/dts/omap3-overo.dtsi @@ -13,6 +13,17 @@ /include/ "omap3.dtsi" +/ { + leds { + compatible = "gpio-leds"; + overo { + label = "overo:blue:COM"; + gpios = <&twl_gpio 19 0>; + linux,default-trigger = "mmc0"; + }; + }; +}; + &i2c1 { clock-frequency = <2600000>; @@ -40,3 +51,7 @@ &mmc2 { bus-width = <4>; }; + +&twl_gpio { + ti,use-leds; +}; -- cgit v0.10.2 From 642f12b4c7505943a6f50101d5b087a74fd9ae72 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 10 Sep 2012 10:20:44 -0700 Subject: arm/dts: Add omap36xx.dtsi file and rename omap3-beagle to omap3-beagle-xm The extra serial port is not available on 34xx. And the current omap3-beagle.dts file is for omap3-beagle-xm.dts as it lists 512MB of memory. Please somebody submit a new omap3-beagle.dts for the original 34xx BeagleBoard after testing it properly. Cc: Benoit Cousson Cc: devicetree-discuss@lists.ozlabs.org Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts new file mode 100644 index 0000000..c38cf76 --- /dev/null +++ b/arch/arm/boot/dts/omap3-beagle-xm.dts @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +/dts-v1/; + +/include/ "omap36xx.dtsi" + +/ { + model = "TI OMAP3 BeagleBoard xM"; + compatible = "ti,omap3-beagle-xm, ti,omap3-beagle", "ti,omap3"; + + memory { + device_type = "memory"; + reg = <0x80000000 0x20000000>; /* 512 MB */ + }; + + leds { + compatible = "gpio-leds"; + pmu_stat { + label = "beagleboard::pmu_stat"; + gpios = <&twl_gpio 19 0>; /* LEDB */ + }; + + heartbeat { + label = "beagleboard::usr0"; + gpios = <&gpio5 22 0>; /* 150 -> D6 LED */ + linux,default-trigger = "heartbeat"; + }; + + mmc { + label = "beagleboard::usr1"; + gpios = <&gpio5 21 0>; /* 149 -> D7 LED */ + linux,default-trigger = "mmc0"; + }; + }; + + sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3beagle"; + + ti,mcbsp = <&mcbsp2>; + ti,codec = <&twl_audio>; + }; +}; + +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + + vsim: regulator-vsim { + compatible = "ti,twl4030-vsim"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + }; + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + codec { + }; + }; + }; +}; + +/include/ "twl4030.dtsi" + +&i2c2 { + clock-frequency = <400000>; +}; + +&i2c3 { + clock-frequency = <100000>; + + /* + * Display monitor features are burnt in the EEPROM + * as EDID data. + */ + eeprom@50 { + compatible = "ti,eeprom"; + reg = <0x50>; + }; +}; + +&mmc1 { + vmmc-supply = <&vmmc1>; + vmmc_aux-supply = <&vsim>; + bus-width = <8>; +}; + +&mmc2 { + status = "disabled"; +}; + +&mmc3 { + status = "disabled"; +}; + +&twl_gpio { + ti,use-leds; + /* pullups: BIT(1) */ + ti,pullups = <0x000002>; + /* + * pulldowns: + * BIT(2), BIT(6), BIT(7), BIT(8), BIT(13) + * BIT(15), BIT(16), BIT(17) + */ + ti,pulldowns = <0x03a1c4>; +}; diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts deleted file mode 100644 index a9d98d5..0000000 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -/dts-v1/; - -/include/ "omap3.dtsi" - -/ { - model = "TI OMAP3 BeagleBoard"; - compatible = "ti,omap3-beagle", "ti,omap3"; - - memory { - device_type = "memory"; - reg = <0x80000000 0x20000000>; /* 512 MB */ - }; - - leds { - compatible = "gpio-leds"; - pmu_stat { - label = "beagleboard::pmu_stat"; - gpios = <&twl_gpio 19 0>; /* LEDB */ - }; - - heartbeat { - label = "beagleboard::usr0"; - gpios = <&gpio5 22 0>; /* 150 -> D6 LED */ - linux,default-trigger = "heartbeat"; - }; - - mmc { - label = "beagleboard::usr1"; - gpios = <&gpio5 21 0>; /* 149 -> D7 LED */ - linux,default-trigger = "mmc0"; - }; - }; - - sound { - compatible = "ti,omap-twl4030"; - ti,model = "omap3beagle"; - - ti,mcbsp = <&mcbsp2>; - ti,codec = <&twl_audio>; - }; -}; - -&i2c1 { - clock-frequency = <2600000>; - - twl: twl@48 { - reg = <0x48>; - interrupts = <7>; /* SYS_NIRQ cascaded to intc */ - interrupt-parent = <&intc>; - - vsim: regulator-vsim { - compatible = "ti,twl4030-vsim"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3000000>; - }; - - twl_audio: audio { - compatible = "ti,twl4030-audio"; - codec { - }; - }; - }; -}; - -/include/ "twl4030.dtsi" - -&i2c2 { - clock-frequency = <400000>; -}; - -&i2c3 { - clock-frequency = <100000>; - - /* - * Display monitor features are burnt in the EEPROM - * as EDID data. - */ - eeprom@50 { - compatible = "ti,eeprom"; - reg = <0x50>; - }; -}; - -&mmc1 { - vmmc-supply = <&vmmc1>; - vmmc_aux-supply = <&vsim>; - bus-width = <8>; -}; - -&mmc2 { - status = "disabled"; -}; - -&mmc3 { - status = "disabled"; -}; - -&twl_gpio { - ti,use-leds; - /* pullups: BIT(1) */ - ti,pullups = <0x000002>; - /* - * pulldowns: - * BIT(2), BIT(6), BIT(7), BIT(8), BIT(13) - * BIT(15), BIT(16), BIT(17) - */ - ti,pulldowns = <0x03a1c4>; -}; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index f024bb3..05c26c4 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -17,7 +17,6 @@ serial0 = &uart1; serial1 = &uart2; serial2 = &uart3; - serial3 = &uart4; }; cpus { @@ -141,12 +140,6 @@ clock-frequency = <48000000>; }; - uart4: serial@49042000 { - compatible = "ti,omap3-uart"; - ti,hwmods = "uart4"; - clock-frequency = <48000000>; - }; - i2c1: i2c@48070000 { compatible = "ti,omap3-i2c"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi new file mode 100644 index 0000000..96bf028 --- /dev/null +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -0,0 +1,25 @@ +/* + * Device Tree Source for OMAP3 SoC + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "omap3.dtsi" + +/ { + aliases { + serial3 = &uart4; + }; + + ocp { + uart4: serial@49042000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart4"; + clock-frequency = <48000000>; + }; + }; +}; diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot index 18813ab..be0fe92 100644 --- a/arch/arm/mach-omap2/Makefile.boot +++ b/arch/arm/mach-omap2/Makefile.boot @@ -3,7 +3,7 @@ params_phys-y := 0x80000100 initrd_phys-y := 0x80800000 dtb-$(CONFIG_SOC_OMAP2420) += omap2420-h4.dtb -dtb-$(CONFIG_ARCH_OMAP3) += omap3-beagle.dtb omap3-evm.dtb omap3-tobi.dtb +dtb-$(CONFIG_ARCH_OMAP3) += omap3-beagle-xm.dtb omap3-evm.dtb omap3-tobi.dtb dtb-$(CONFIG_ARCH_OMAP4) += omap4-panda.dtb omap4-pandaES.dtb dtb-$(CONFIG_ARCH_OMAP4) += omap4-var_som.dtb omap4-sdp.dtb dtb-$(CONFIG_SOC_OMAP5) += omap5-evm.dtb -- cgit v0.10.2 From 679e33104dbf9b78d88b812fc3c1ac88536d24bf Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 10 Sep 2012 10:34:51 -0700 Subject: arm/dts: Add pinctrl driver entries for omap2/3/4 Add pinctrl driver entries for omap2+. These all use the generic pinctrl-single driver for the padconf registers. Cc: devicetree-discuss@lists.ozlabs.org Acked-by: Linus Walleij [tony@atomide.com: updated to drop omap2420.dtsi rename changes] Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi index 6174d3d..bfd76b4 100644 --- a/arch/arm/boot/dts/omap2420.dtsi +++ b/arch/arm/boot/dts/omap2420.dtsi @@ -14,6 +14,15 @@ compatible = "ti,omap2420", "ti,omap2"; ocp { + omap2420_pmx: pinmux@48000030 { + compatible = "ti,omap2420-padconf", "pinctrl-single"; + reg = <0x48000030 0x0113>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <8>; + pinctrl-single,function-mask = <0x3f>; + }; + mcbsp1: mcbsp@48074000 { compatible = "ti,omap2420-mcbsp"; reg = <0x48074000 0xff>; diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi index 59a639a..4565d97 100644 --- a/arch/arm/boot/dts/omap2430.dtsi +++ b/arch/arm/boot/dts/omap2430.dtsi @@ -14,6 +14,15 @@ compatible = "ti,omap2430", "ti,omap2"; ocp { + omap2430_pmx: pinmux@49002030 { + compatible = "ti,omap2430-padconf", "pinctrl-single"; + reg = <0x49002030 0x0154>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <8>; + pinctrl-single,function-mask = <0x3f>; + }; + mcbsp1: mcbsp@48074000 { compatible = "ti,omap2430-mcbsp"; reg = <0x48074000 0xff>; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index 05c26c4..f38ea87 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -68,6 +68,24 @@ reg = <0x48200000 0x1000>; }; + omap3_pmx_core: pinmux@48002030 { + compatible = "ti,omap3-padconf", "pinctrl-single"; + reg = <0x48002030 0x05cc>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0x7fff>; + }; + + omap3_pmx_wkup: pinmux@0x48002a58 { + compatible = "ti,omap3-padconf", "pinctrl-single"; + reg = <0x48002a58 0x5c>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0x7fff>; + }; + gpio1: gpio@48310000 { compatible = "ti,omap3-gpio"; ti,hwmods = "gpio1"; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 75095e3..5d1c484 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -95,6 +95,23 @@ ranges; ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3"; + omap4_pmx_core: pinmux@4a100040 { + compatible = "ti,omap4-padconf", "pinctrl-single"; + reg = <0x4a100040 0x0196>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0x7fff>; + }; + omap4_pmx_wkup: pinmux@4a31e040 { + compatible = "ti,omap4-padconf", "pinctrl-single"; + reg = <0x4a31e040 0x0038>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0x7fff>; + }; + gpio1: gpio@4a310000 { compatible = "ti,omap4-gpio"; reg = <0x4a310000 0x200>; -- cgit v0.10.2 From 8f31cefe32b9c6bcab43e0ec79fb26393d5c7713 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Mon, 10 Sep 2012 10:34:52 -0700 Subject: ARM: OMAP2+: select PINCTRL in Kconfig Select PINCTRL in Kconfig under Typical OMAP configuration, this is required to add pinctrl driver to omap2+ family of devices. Signed-off-by: AnilKumar Ch [tony@atomide.com: updated to select pinctrl-single in defconfig] Signed-off-by: Tony Lindgren diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index e58edc3..6230304 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -123,6 +123,7 @@ CONFIG_HW_RANDOM=y CONFIG_I2C_CHARDEV=y CONFIG_SPI=y CONFIG_SPI_OMAP24XX=y +CONFIG_PINCTRL_SINGLE=y CONFIG_DEBUG_GPIO=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_TWL4030=y diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 4a4d058..e45bbff 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -18,6 +18,7 @@ config ARCH_OMAP2PLUS_TYPICAL select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4 select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4 select HIGHMEM + select PINCTRL help Compile a kernel suitable for booting most boards -- cgit v0.10.2 From 26638c667e645de368cd68cade716ed0faef6269 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 10 Sep 2012 10:34:52 -0700 Subject: arm/dts: Mux uart pins for omap4-sdp Mux uart pins for the serial ports. Signed-off-by: Tony Lindgren diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 7e83a61..94a23b3 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -116,6 +116,33 @@ }; }; +&omap4_pmx_core { + uart2_pins: pinmux_uart2_pins { + pinctrl-single,pins = < + 0xd8 0x118 /* uart2_cts.uart2_cts INPUT_PULLUP | MODE0 */ + 0xda 0 /* uart2_rts.uart2_rts OUTPUT | MODE0 */ + 0xdc 0x118 /* uart2_rx.uart2_rx INPUT_PULLUP | MODE0 */ + 0xde 0 /* uart2_tx.uart2_tx OUTPUT | MODE0 */ + >; + }; + + uart3_pins: pinmux_uart3_pins { + pinctrl-single,pins = < + 0x100 0x118 /* uart3_cts_rctx.uart3_cts_rctx INPUT_PULLUP | MODE0 */ + 0x102 0 /* uart3_rts_sd.uart3_rts_sd OUTPUT | MODE0 */ + 0x104 0x100 /* uart3_rx_irrx.uart3_rx_irrx INPUT | MODE0 */ + 0x106 0 /* uart3_tx_irtx.uart3_tx_irtx OUTPUT | MODE0 */ + >; + }; + + uart4_pins: pinmux_uart4_pins { + pinctrl-single,pins = < + 0x11c 0x100 /* uart4_rx.uart4_rx INPUT | MODE0 */ + 0x11e 0 /* uart4_tx.uart4_tx OUTPUT | MODE0 */ + >; + }; +}; + &i2c1 { clock-frequency = <400000>; @@ -307,3 +334,18 @@ 0x0707006c>; /* KEY_DOWN */ linux,input-no-autorepeat; }; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins>; +}; -- cgit v0.10.2 From 761d4c9d5c213a08129523f6f452333516a2dd7c Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Wed, 29 Aug 2012 02:18:49 +0300 Subject: ARM: OMAP: cleanup struct omap_board_config_kernel struct omap_board_config_kernel defined in the board files is always empty and does not bring any added value. Remove the struct omap_board_config_kernel instances from the board files. Also remove the omap_get_nr_config() macro and the omap_get_var_config() function as both are not used for quite a long time (if ever). Signed-off-by: Igor Grinberg Signed-off-by: Tony Lindgren diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c index 6ec385e..d032734 100644 --- a/arch/arm/mach-omap1/board-generic.c +++ b/arch/arm/mach-omap1/board-generic.c @@ -52,9 +52,6 @@ static struct omap_usb_config generic1610_usb_config __initdata = { }; #endif -static struct omap_board_config_kernel generic_config[] __initdata = { -}; - static void __init omap_generic_init(void) { #ifdef CONFIG_ARCH_OMAP15XX @@ -76,8 +73,6 @@ static void __init omap_generic_init(void) } #endif - omap_board_config = generic_config; - omap_board_config_size = ARRAY_SIZE(generic_config); omap_serial_init(); omap_register_i2c_bus(1, 100, NULL, 0); } diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index 3497769..11e1ff3 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -155,9 +155,6 @@ static struct omap_usb_config voiceblue_usb_config __initdata = { .pins[2] = 6, }; -static struct omap_board_config_kernel voiceblue_config[] = { -}; - #define MACHINE_PANICED 1 #define MACHINE_REBOOTING 2 #define MACHINE_REBOOT 4 @@ -275,8 +272,6 @@ static void __init voiceblue_init(void) voiceblue_smc91x_resources[1].start = gpio_to_irq(8); voiceblue_smc91x_resources[1].end = gpio_to_irq(8); platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices)); - omap_board_config = voiceblue_config; - omap_board_config_size = ARRAY_SIZE(voiceblue_config); omap_serial_init(); omap1_usb_init(&voiceblue_usb_config); omap_register_i2c_bus(1, 100, NULL, 0); diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index a98c688..0f78cdb 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -31,7 +31,6 @@ #include #include -#include #include #include "common.h" #include @@ -191,9 +190,6 @@ static struct omap_dss_board_info sdp3430_dss_data = { .default_device = &sdp3430_lcd_device, }; -static struct omap_board_config_kernel sdp3430_config[] __initdata = { -}; - static struct omap2_hsmmc_info mmc[] = { { .mmc = 1, @@ -576,8 +572,6 @@ static void __init omap_3430sdp_init(void) int gpio_pendown; omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); - omap_board_config = sdp3430_config; - omap_board_config_size = ARRAY_SIZE(sdp3430_config); omap_hsmmc_init(mmc); omap3430_i2c_init(); omap_display_init(&sdp3430_dss_data); diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c index 2dc9ba5..8518b13 100644 --- a/arch/arm/mach-omap2/board-3630sdp.c +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -17,7 +17,6 @@ #include #include "common.h" -#include #include #include @@ -67,9 +66,6 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = { .reset_gpio_port[2] = -EINVAL }; -static struct omap_board_config_kernel sdp_config[] __initdata = { -}; - #ifdef CONFIG_OMAP_MUX static struct omap_board_mux board_mux[] __initdata = { { .reg_offset = OMAP_MUX_TERMINATOR }, @@ -197,8 +193,6 @@ static struct flash_partitions sdp_flash_partitions[] = { static void __init omap_sdp_init(void) { omap3_mux_init(board_mux, OMAP_PACKAGE_CBP); - omap_board_config = sdp_config; - omap_board_config_size = ARRAY_SIZE(sdp_config); zoom_peripherals_init(); omap_sdrc_init(h8mbx00u0mer0em_sdrc_params, h8mbx00u0mer0em_sdrc_params); diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c index 92432c2..de92b08 100644 --- a/arch/arm/mach-omap2/board-am3517crane.c +++ b/arch/arm/mach-omap2/board-am3517crane.c @@ -26,7 +26,6 @@ #include #include -#include #include "common.h" #include @@ -37,11 +36,6 @@ #define GPIO_USB_POWER 35 #define GPIO_USB_NRESET 38 - -/* Board initialization */ -static struct omap_board_config_kernel am3517_crane_config[] __initdata = { -}; - #ifdef CONFIG_OMAP_MUX static struct omap_board_mux board_mux[] __initdata = { { .reg_offset = OMAP_MUX_TERMINATOR }, @@ -67,9 +61,6 @@ static void __init am3517_crane_init(void) omap_serial_init(); omap_sdrc_init(NULL, NULL); - omap_board_config = am3517_crane_config; - omap_board_config_size = ARRAY_SIZE(am3517_crane_config); - /* Configure GPIO for EHCI port */ if (omap_mux_init_gpio(GPIO_USB_NRESET, OMAP_PIN_OUTPUT)) { pr_err("Can not configure mux for GPIO_USB_NRESET %d\n", diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 18f6010..00abda1 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -32,7 +32,6 @@ #include #include -#include #include "common.h" #include #include